Pilz.Net erstellen
176
Pilz.Net.md
Normal file
176
Pilz.Net.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# WebApi
|
||||||
|
|
||||||
|
`Pilz.Net.Api` introduces a very simple way to create a WebApi server and client. It's an alternative to the implemenation in ASP.NET which uses `Newtonsoft.Json` instead of `Json.NET` and is even more easier to implement and more extendable via plugins. As of now `Pilz.Net.Api` not fully REST compliant, this might be fixed in the future (PRs welcome).
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
The process is simple:
|
||||||
|
1. The client sends a request with a given URL and an optional message to the server.
|
||||||
|
2. The server evaluates the request and response containing a status code and an optional a new message.
|
||||||
|
3. The client gets the response and *can* evaluate it, but doesn't need to.
|
||||||
|
|
||||||
|
## Client
|
||||||
|
|
||||||
|
### Create new ApiClient
|
||||||
|
|
||||||
|
You can either use the pre-difined `ApiClient` or create your own by implementing `IApiClient`. Pass throw the api base url.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
var client = new ApiClient("http://localhost");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Make a request
|
||||||
|
|
||||||
|
Creating a request can be done with the asyncron `IApiClient.MakeRequest()` and `IApiClient.MakeRequest<T>()` methods. You need to pass throw the api url (relative to the api base url). Optionally you can also pass an `ApiMessage` instance or your own `IApiMessageSerializer`.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
// Run asyncron
|
||||||
|
var result = await client.SendRequest<SDxResponse>("/sdx/get");
|
||||||
|
|
||||||
|
// Run syncron
|
||||||
|
var result = client.SendRequest<SDxResponse>("/sdx/get").Result;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check result
|
||||||
|
|
||||||
|
The result is always an instance of `ApiResponse` and contains the status code or the optional response message.
|
||||||
|
|
||||||
|
You have several ways to check the status code:
|
||||||
|
- Check the status code manually via `StatusCode` for more detailed check.
|
||||||
|
- Check the status code via the method `IsOk()` which returns an boolean if the `StatusCode` is `Ok` and the `Message` is not null.
|
||||||
|
- Check the status code via the method `EnsureOk()` which throws an exception if the `StatusCode` is not `Ok` and `Message` is not null.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
// Check manually
|
||||||
|
If (result.StatusCode == HttpStatusCode.OK)
|
||||||
|
// ...
|
||||||
|
else
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Check via IsOk()
|
||||||
|
If (result.IsOk())
|
||||||
|
// ...
|
||||||
|
else
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Check via EnsureOk()
|
||||||
|
result.EnsureOk();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check message
|
||||||
|
|
||||||
|
If the status code is fine and the message is not null, you can use it. It's typed as `T` while `T` is an type that inherits from `ApiMessage` which you can define at `SendRequest<T>()` method.
|
||||||
|
|
||||||
|
## Server
|
||||||
|
|
||||||
|
### Create new ApiServer
|
||||||
|
|
||||||
|
You can either use the pre-difined `ApiServer` or create your own by implementing `IApiServer`. Pass throw the api base url.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
var server = new Apiserver("http://localhost");
|
||||||
|
```
|
||||||
|
|
||||||
|
Register your own handlers or let your plugins register their handlers anonymously.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
// Register object instance
|
||||||
|
// This registers all private and public methods with the `ApiMessageHandler` attribute.
|
||||||
|
server.RegisterHandler(new SDxApiServer());
|
||||||
|
|
||||||
|
// Register single method
|
||||||
|
server.Register(MyMethod);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create message handlers
|
||||||
|
|
||||||
|
When a request reaches the server then the server checks each registered handler method for its `ApiMessageHandler` attribute.
|
||||||
|
- The return value of the method always needs to be an instance of `ApiResult`.
|
||||||
|
- The method itself can be private or public.
|
||||||
|
- The `ApiMessageHandler` defines the api url (relative to the api base url) and optionally if authentication is requied for this request and also an serializer type for deseralizing the ApiMessage.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
[ApiMessageHandler("/sdx/get")]
|
||||||
|
private ApiResult GetSDx()
|
||||||
|
{
|
||||||
|
return ApiResult.Ok(new SDxResponse(Database.SDxList.Select(s => s.ToClient())));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If your request can have an (optional) message, you can define a parameter with the target message type.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
[ApiMessageHandler("/sdx/get")]
|
||||||
|
private ApiResult GetSDx(SDxGetRequest message)
|
||||||
|
{
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
if (Database.SDxList.FirstOrDefault(s => s.Id == message.Id) is not SDx sdx)
|
||||||
|
return ApiResult.NotFound();
|
||||||
|
return ApiResult.Ok(new SDxGetResponse(sdx);
|
||||||
|
}
|
||||||
|
return ApiResult.Ok(new SDxGetResponse(Database.SDxList.Select(s => s.ToClient())));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need the whole request, you can define a parameter with the `ApiRequest` instance which also contains the `ApiMessage`, if available. However, you can even define both parameters at the same time, if you want. The `ApiRequest` can be useful if you want to check authentication conditionally depenting on the request message instead of defined `RequiesAuth = true` at the parameter.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
[ApiMessageHandler("/sdx/get")]
|
||||||
|
private ApiResult GetSDx(ApiRequest request, SDxGetRequest message)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
For authentication you can either use the pre-defined events or create your own Server and Client class. Either inherit from `ApiServer`/`ApiClient` or create your complete own implementation by implement `IApiServer`/`IApiClient`. However, the `ApiServer` and `ApiClient` classes has some pre-defined methods you can overwrite to easily check the authentication.
|
||||||
|
|
||||||
|
### Use events
|
||||||
|
|
||||||
|
You can use the event for one-way and two-way encryption.
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
|
||||||
|
Register this method to the `ApiClient.OnEcryptAuthKey` event. Encode the authKey (unencrypted) and return the decrypted value.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
protected virtual string? EncodeAuthKey()
|
||||||
|
{
|
||||||
|
return AuthKey;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Server
|
||||||
|
|
||||||
|
Register this method to the `ApiServer.OnCheckAuthentication` event. Decode the authKey (encrypted) and return the decrypted value.
|
||||||
|
|
||||||
|
```cs
|
||||||
|
protected virtual string? DecodeAuthKey(string authKey)
|
||||||
|
{
|
||||||
|
return authKey;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inherit & Overwrite
|
||||||
|
|
||||||
|
You can use this way for one-way and two-way encryption. For one-way encryption you should overwrite `CheckAuthentication` instead of `DecodeAuthKey` and may not need `EncodeAuthKey` (depending on your security implementation.
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
|
||||||
|
```cs
|
||||||
|
protected virtual string? EncodeAuthKey()
|
||||||
|
{
|
||||||
|
return AuthKey;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Server
|
||||||
|
|
||||||
|
```cs
|
||||||
|
protected virtual string? DecodeAuthKey(string authKey)
|
||||||
|
{
|
||||||
|
return authKey;
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user