api: add events to control api requests via context
This commit is contained in:
@@ -7,6 +7,10 @@ public class ApiClient(string apiUrl) : IApiClient
|
|||||||
{
|
{
|
||||||
protected readonly List<object> clients = [];
|
protected readonly List<object> clients = [];
|
||||||
|
|
||||||
|
public event ApiRequestCancelEventHandler? OnApiRequestStart;
|
||||||
|
public event ApiRequestEventHandler? OnApiRequestResponse;
|
||||||
|
public event ApiRequestEventHandler? OnApiRequestCompleted;
|
||||||
|
|
||||||
public HttpClient HttpClient { get; set; } = new();
|
public HttpClient HttpClient { get; set; } = new();
|
||||||
|
|
||||||
public virtual string ApiUrl { get; } = apiUrl;
|
public virtual string ApiUrl { get; } = apiUrl;
|
||||||
@@ -36,50 +40,66 @@ public class ApiClient(string apiUrl) : IApiClient
|
|||||||
|
|
||||||
public virtual async Task<ApiResponse> SendRequest(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer? serializer)
|
public virtual async Task<ApiResponse> SendRequest(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer? serializer)
|
||||||
{
|
{
|
||||||
serializer ??= Serializer;
|
|
||||||
|
|
||||||
Log.InfoFormat("Send message to {0}", route);
|
Log.InfoFormat("Send message to {0}", route);
|
||||||
|
|
||||||
var res = await Send(route, method, message, @params, serializer);
|
var context = new ApiRequestContext(route, method, message, @params, serializer, null);
|
||||||
|
await Send(context);
|
||||||
|
|
||||||
return new(res);
|
var response = new ApiResponse(context.HttpResponse);
|
||||||
|
context.ApiResponse = response;
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResponse<TResponse>> SendRequest<TResponse>(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer? serializer) where TResponse : ApiMessage
|
public virtual async Task<ApiResponse<TResponse>> SendRequest<TResponse>(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer? serializer) where TResponse : ApiMessage
|
||||||
{
|
{
|
||||||
serializer ??= Serializer;
|
|
||||||
|
|
||||||
Log.InfoFormat("Send request to {0}", route);
|
Log.InfoFormat("Send request to {0}", route);
|
||||||
|
|
||||||
var res = await Send(route, method, message, @params, serializer);
|
var context = new ApiRequestContext(route, method, message, @params, serializer, typeof(TResponse));
|
||||||
|
await Send(context);
|
||||||
TResponse? result = null;
|
TResponse? result = null;
|
||||||
|
|
||||||
if (res.IsSuccessStatusCode)
|
if (context.HttpResponse != null && context.HttpResponse.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
var mediaType = res.Content.Headers.ContentType?.MediaType;
|
var mediaType = context.HttpResponse.Content.Headers.ContentType?.MediaType;
|
||||||
if (!string.IsNullOrWhiteSpace(mediaType))
|
if (!string.IsNullOrWhiteSpace(mediaType))
|
||||||
{
|
{
|
||||||
if (mediaType == "application/json")
|
if (mediaType == "application/json" && context.Serializer != null)
|
||||||
result = serializer.Deserialize(await res.Content.ReadAsStringAsync(), typeof(TResponse)) as TResponse;
|
result = context.Serializer.Deserialize(await context.HttpResponse.Content.ReadAsStringAsync(), typeof(TResponse)) as TResponse;
|
||||||
else if (typeof(TResponse).IsAssignableTo(typeof(ApiRawMessage)) && mediaType == "application/octet-stream")
|
else if (typeof(TResponse).IsAssignableTo(typeof(ApiRawMessage)) && mediaType == "application/octet-stream")
|
||||||
result = (TResponse)(object)new ApiRawMessage(await res.Content.ReadAsByteArrayAsync());
|
result = (TResponse)(object)new ApiRawMessage(await context.HttpResponse.Content.ReadAsByteArrayAsync());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(res, result);
|
var response = new ApiResponse<TResponse>(context.HttpResponse, result);
|
||||||
|
context.ApiResponse = response;
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task<HttpResponseMessage> Send(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer serializer)
|
protected virtual async Task Send(ApiRequestContext context)
|
||||||
{
|
{
|
||||||
var url = ApiUrl + route + BuildParameters(@params);
|
var url = ApiUrl + context.Route + BuildParameters(context.Params);
|
||||||
HttpContent content;
|
HttpContent content;
|
||||||
|
context.Serializer ??= Serializer;
|
||||||
|
|
||||||
Log.DebugFormat("Api endpoint url is {0}", url);
|
Log.DebugFormat("Api endpoint url is {0}", url);
|
||||||
|
|
||||||
|
if (OnApiRequestStart != null)
|
||||||
|
{
|
||||||
|
var args = new ApiRequestCancelEventArgs(context);
|
||||||
|
OnApiRequestStart.Invoke(this, args);
|
||||||
|
if (args.Cancel)
|
||||||
|
{
|
||||||
|
context.Canceled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.Debug("Create content");
|
Log.Debug("Create content");
|
||||||
|
|
||||||
if (message is not null)
|
if (context.Message is not null)
|
||||||
content = new StringContent(serializer.Serialize(message)!, null, "application/json");
|
content = new StringContent(context.Serializer.Serialize(context.Message)!, null, "application/json");
|
||||||
else
|
else
|
||||||
content = new StringContent(string.Empty, null, "application/json");
|
content = new StringContent(string.Empty, null, "application/json");
|
||||||
|
|
||||||
@@ -89,12 +109,14 @@ public class ApiClient(string apiUrl) : IApiClient
|
|||||||
|
|
||||||
Log.Debug("Sending request");
|
Log.Debug("Sending request");
|
||||||
|
|
||||||
var httpmsg = new HttpRequestMessage(method, url)
|
var httpmsg = new HttpRequestMessage(context.Method, url)
|
||||||
{
|
{
|
||||||
Content = content
|
Content = content
|
||||||
};
|
};
|
||||||
|
|
||||||
return await HttpClient.SendAsync(httpmsg);
|
context.HttpResponse = await HttpClient.SendAsync(httpmsg);
|
||||||
|
|
||||||
|
OnApiRequestResponse?.Invoke(this, new(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string BuildParameters(ApiParameterCollection? @params)
|
protected virtual string BuildParameters(ApiParameterCollection? @params)
|
||||||
|
|||||||
10
Pilz.Net/Api/ApiRequestCancelEventArgs.cs
Normal file
10
Pilz.Net/Api/ApiRequestCancelEventArgs.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
|
public delegate void ApiRequestCancelEventHandler(object sender, ApiRequestCancelEventArgs e);
|
||||||
|
|
||||||
|
public class ApiRequestCancelEventArgs(ApiRequestContext context) : CancelEventArgs
|
||||||
|
{
|
||||||
|
public ApiRequestContext Context => context;
|
||||||
|
}
|
||||||
24
Pilz.Net/Api/ApiRequestContext.cs
Normal file
24
Pilz.Net/Api/ApiRequestContext.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
|
public class ApiRequestContext
|
||||||
|
{
|
||||||
|
public bool Canceled { get; internal set; }
|
||||||
|
public string Route { get; set; }
|
||||||
|
public HttpMethod Method { get; set; }
|
||||||
|
public ApiMessage? Message { get; set; }
|
||||||
|
public ApiParameterCollection? Params { get; }
|
||||||
|
public IApiMessageSerializer? Serializer { get; set; }
|
||||||
|
public Type? ResponseMessageType { get; }
|
||||||
|
public HttpResponseMessage? HttpResponse { get; internal set; }
|
||||||
|
public object? ApiResponse { get; internal set; }
|
||||||
|
|
||||||
|
public ApiRequestContext(string route, HttpMethod method, ApiMessage? message, ApiParameterCollection? @params, IApiMessageSerializer? serializer, Type? responseMessageType)
|
||||||
|
{
|
||||||
|
Route = route;
|
||||||
|
Method = method;
|
||||||
|
Message = message;
|
||||||
|
Params = @params;
|
||||||
|
Serializer = serializer;
|
||||||
|
ResponseMessageType = responseMessageType;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Pilz.Net/Api/ApiRequestEventArgs.cs
Normal file
8
Pilz.Net/Api/ApiRequestEventArgs.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
|
public delegate void ApiRequestEventHandler(object sender, ApiRequestEventArgs e);
|
||||||
|
|
||||||
|
public class ApiRequestEventArgs(ApiRequestContext context) : EventArgs
|
||||||
|
{
|
||||||
|
public ApiRequestContext Context => context;
|
||||||
|
}
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
namespace Pilz.Net.Api;
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
public record class ApiResponse(
|
public record class ApiResponse(
|
||||||
HttpResponseMessage Response)
|
HttpResponseMessage? Response)
|
||||||
{
|
{
|
||||||
public HttpStatusCode StatusCode => Response.StatusCode;
|
public HttpStatusCode StatusCode => Response?.StatusCode ?? default;
|
||||||
|
|
||||||
public bool IsOk => (int)StatusCode >= 200 && (int)StatusCode <= 299;
|
public bool IsOk => (int)StatusCode >= 200 && (int)StatusCode <= 299;
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ using System.Net;
|
|||||||
namespace Pilz.Net.Api;
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
public record class ApiResponse<T>(
|
public record class ApiResponse<T>(
|
||||||
HttpResponseMessage Response,
|
HttpResponseMessage? Response,
|
||||||
T? Message)
|
T? Message)
|
||||||
where T : ApiMessage
|
where T : ApiMessage
|
||||||
{
|
{
|
||||||
public HttpStatusCode StatusCode => Response.StatusCode;
|
public HttpStatusCode StatusCode => Response?.StatusCode ?? default;
|
||||||
|
|
||||||
[MemberNotNullWhen(true, nameof(Message))]
|
[MemberNotNullWhen(true, nameof(Message))]
|
||||||
public bool IsOk => (int)StatusCode >= 200 && (int)StatusCode <= 299 && Message is not null;
|
public bool IsOk => (int)StatusCode >= 200 && (int)StatusCode <= 299 && Message is not null;
|
||||||
|
|||||||
Reference in New Issue
Block a user