日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

走进WebApiClientCore的设计

發布時間:2023/12/4 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 走进WebApiClientCore的设计 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

WebApiClient

WebApiClient是NCC開源社區的一個項目,是目前微服務里http接口調用的一把鋒利尖刀,項目早期設計與開發的時候,是基于.netframework的,然后慢慢加入netstandard和netcoreapp多個框架的支持,設計能力出眾,AOP能力唾手可得易如反掌。

WebApiClientCore

WebApiClient很優秀,它將不同框架不同平臺都實現了統一的api;WebApiClient不夠優秀,它在.netcore下完全可以更好,但它不得不兼容.net45開始所有框架而有所犧牲。所以WebApiClientCore橫空出世,它是WebApiClient.JIT的.netcore替代版本,目前尚屬于alpha階段,計劃只支持.netcore平臺,并緊密與.netcore新特性緊密結合。

WebApiClientCore的變化

  • 使用System.Text.Json替換Json.net,提升序列化性能

  • 移除HttpApiFactory和HttApiConfig功能,使用Microsoft.Extensions.Http的HttpClientFactory

  • 移除AOT功能,僅保留依賴于Emit的運行時代理

  • 高效的ActionInvoker,對返回Task<>和ITask<>作不同處理

  • 所有特性都都變成中間件,基于管道編排各個特性并生成Action執行委托

  • 良好設計的HttpContext、ApiRequestContext、ApiParameterContext和ApiResponseContext

WebApiClientCore執行流程設計

1 接口代理類生成設計

Cretate<THttpApi>() -> BuildProxyType() -> CreateProxyInstance(ActionInterceptor)

1.1 HttpApiProxyTypeBuilder

在HttpApi.Create()時,先調用HttpApiProxyTypeBuilder來生成THttpApi接口的代理類,HttpApiProxyTypeBuilder是基于Emit方案,Build出來的代理類在每個方法調用時觸發一次攔截器ActionInterceptor的Intercept()方法,將調用參數傳給攔截器。

1.2 HttpApiProxyBuilder

給定一個代理類的類型(Type),快速生成代理類的實例,這個Builder實際是生成并保存了代理類構造器的高效調用委托,屬于反射優化。

2 ActionInterceptor的設計

ActionInterceptor.Intercept(MethodInfo) -> CreateActionInvoker() -> ActionInvoker.Invoke()

ActionInterceptor在攔截到方法調用時,根據方法的MethodInfo信息,創建ActionInvoker,然后調用ActionInvoker.Invoke()執行。當然,ActionInvoker并不是總是創建的,因為它的創建是有成本的,ActionInterceptor使用了緩存ActionInvoker的方案。

2.1 MultiplexedActionInvoker

WebApiClientCore支持加Task<>和ITask<>兩種異步聲明,MultiplexedActionInvoker實際上包裝了ActionInvoker和ActionTask兩個字段,當聲明為Task<>時,調用ActionInvoker執行,當聲明為ITask<>是,返回創建實現了ITask<>接口的ActionTask實例。

2.2 ActionInvoker

ActionInvoker是一個ApiActionDescriptor的執行器,其實現了IActionInvoker.Invoke(ServiceContext context, object[] arguments)接口。關于Descriptor的設計模式,我們在asp.netcore的各種AtionContext里可以發現,有了ApiActionDescriptor,再給它各個參數值,Action就很容易執行起來了。

3 RequestDelegate生成設計

ActionInvoker在拿到各個參數值之后,并不是直接從ApiActionDescriptor查找各個特性來執行,而是在執行前就把執行流程編譯好,得到一個執行委托,這個委托叫RequestDelegate,其原型為Func<ApiRequestContext, Task<ApiResponseContext>> Build(ApiActionDescriptor apiAction)。抽象成傳入請求上下文件,返回響應上下文,當真正執行時,調用這個委托即可。如果你熟悉asp.netcore,那么應該很容易理解下面代碼的思路:

/// <summary>
/// 提供Action的調用鏈委托創建
/// </summary>
static class RequestDelegateBuilder
{
/// <summary>
/// 創建執行委托
/// </summary>
/// <returns></returns>
public static Func<ApiRequestContext, Task<ApiResponseContext>> Build(ApiActionDescriptor apiAction)
{
var requestHandler = BuildRequestHandler(apiAction);
var responseHandler = BuildResponseHandler(apiAction);

return async request =>
{
await requestHandler(request).ConfigureAwait(false);
var response = await SendRequestAsync(request).ConfigureAwait(false);
await responseHandler(response).ConfigureAwait(false);
return response;
};
}


/// <summary>
/// 創建請求委托
/// </summary>
/// <param name="apiAction"></param>
/// <returns></returns>
private static InvokeDelegate<ApiRequestContext> BuildRequestHandler(ApiActionDescriptor apiAction)
{
var builder = new PipelineBuilder<ApiRequestContext>();

// 參數驗證特性驗證和參數模型屬性特性驗證
builder.Use(next => context =>
{
var validateProperty = context.HttpContext.Options.UseParameterPropertyValidate;
foreach (var parameter in context.ApiAction.Parameters)
{
var parameterValue = context.Arguments[parameter.Index];
ApiValidator.ValidateParameter(parameter, parameterValue, validateProperty);
}
return next(context);
});

// action特性請求前執行
foreach (var attr in apiAction.Attributes)
{
builder.Use(attr.OnRequestAsync);
}

// 參數特性請求前執行
foreach (var parameter in apiAction.Parameters)
{
var index = parameter.Index;
foreach (var attr in parameter.Attributes)
{
builder.Use(async (context, next) =>
{
var ctx = new ApiParameterContext(context, index);
await attr.OnRequestAsync(ctx, next).ConfigureAwait(false);
});
}
}

// Return特性請求前執行
foreach (var @return in apiAction.Return.Attributes)
{
if (@return.Enable == true)
{
builder.Use(@return.OnRequestAsync);
}
}

// Filter請求前執行
foreach (var filter in apiAction.FilterAttributes)
{
if (filter.Enable == true)
{
builder.Use(filter.OnRequestAsync);
}
}

return builder.Build();
}

/// <summary>
/// 創建響應委托
/// </summary>
/// <param name="apiAction"></param>
/// <returns></returns>
private static InvokeDelegate<ApiResponseContext> BuildResponseHandler(ApiActionDescriptor apiAction)
{
var builder = new PipelineBuilder<ApiResponseContext>();

// Return特性請求后執行
foreach (var @return in apiAction.Return.Attributes)
{
if (@return.Enable == false)
{
continue;
}

builder.Use(async (context, next) =>
{
if (context.ResultStatus == ResultStatus.None)
{
await @return.OnResponseAsync(context, next).ConfigureAwait(false);
}
else
{
await next().ConfigureAwait(false);
}
});
}

// 驗證Result是否ok
builder.Use(next => context =>
{
try
{
ApiValidator.ValidateReturnValue(context.Result, context.HttpContext.Options.UseReturnValuePropertyValidate);
}
catch (Exception ex)
{
context.Exception = ex;
}
return next(context);
});

// Filter請求后執行
foreach (var filter in apiAction.FilterAttributes)
{
if (filter.Enable == true)
{
builder.Use(filter.OnResponseAsync);
}
}

return builder.Build();
}


/// <summary>
/// 執行http請求
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private static async Task<ApiResponseContext> SendRequestAsync(ApiRequestContext context)
{
try
{
var apiCache = new ApiCache(context);
var cacheValue = await apiCache.GetAsync().ConfigureAwait(false);

if (cacheValue != null && cacheValue.Value != null)
{
context.HttpContext.ResponseMessage = cacheValue.Value;
}
else
{
using var cancellation = CreateLinkedTokenSource(context);
var response = await context.HttpContext.Client.SendAsync(context.HttpContext.RequestMessage, cancellation.Token).ConfigureAwait(false);

context.HttpContext.ResponseMessage = response;
await apiCache.SetAsync(cacheValue?.Key, response).ConfigureAwait(false);
}
return new ApiResponseContext(context);
}
catch (Exception ex)
{
return new ApiResponseContext(context) { Exception = ex };
}
}

/// <summary>
/// 創建取消令牌源
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private static CancellationTokenSource CreateLinkedTokenSource(ApiRequestContext context)
{
if (context.CancellationTokens.Count == 0)
{
return CancellationTokenSource.CreateLinkedTokenSource(CancellationToken.None);
}
else
{
var tokens = context.CancellationTokens.ToArray();
return CancellationTokenSource.CreateLinkedTokenSource(tokens);
}
}

}

WebApiClientCore的特性設計

WebApiClientCore的核心特性為以下4種,每種功能各不一樣,在設計上使用了中間件的思想,每一步執行都可以獲取到context對象和下一個中間件next對象,開發者在實現自定義Attribute時,可以選擇性的進行短路設計。

1 IApiActionAttribute

表示Action執行前會調用,調用時接收到ApiRequestContext

/// <summary> /// 定義ApiAction修飾特性的行為 /// </summary> public interface IApiActionAttribute : IAttributeMultiplable {/// <summary>/// 請求前/// </summary>/// <param name="context">上下文</param>/// <param name="next">下一個執行委托</param>/// <returns></returns>Task OnRequestAsync(ApiRequestContext context, Func<Task> next); }

2 IApiParameterAttribute

表示參數執行前會調用,調用時接收到ApiParameterContext

/// <summary> /// 定義Api參數修飾特性的行為 /// </summary> public interface IApiParameterAttribute {/// <summary>/// 請求前/// </summary>/// <param name="context">上下文</param>/// <param name="next">下一個執行委托</param>/// <returns></returns>Task OnRequestAsync(ApiParameterContext context, Func<Task> next); }

3 IApiReturnAttribute

執行前和執行后都會收到,設置為上下文的Result或Exception,會短路執行

/// <summary> /// 定義回復內容處理特性的行為 /// </summary> public interface IApiReturnAttribute : IAttributeMultiplable, IAttributeEnable {/// <summary>/// 請求前/// </summary>/// <param name="context">上下文</param>/// <param name="next">下一個執行委托</param>/// <returns></returns>Task OnRequestAsync(ApiRequestContext context, Func<Task> next);/// <summary>/// 響應后/// </summary>/// <param name="context">上下文</param>/// <param name="next">下一個執行委托</param>/// <returns></returns>Task OnResponseAsync(ApiResponseContext context, Func<Task> next); }

5 IApiFilterAttribute

執行前和執行后都會收到,在IApiReturnAttribute之后執行

/// <summary>
/// 定義ApiAction過濾器修飾特性的行為
/// </summary>
public interface IApiFilterAttribute : IAttributeMultiplable, IAttributeEnable
{
/// <summary>
/// 請求前
/// </summary>
/// <param name="context">上下文</param>
/// <param name="next">下一個執行委托</param>
/// <returns></returns>
Task OnRequestAsync(ApiRequestContext context, Func<Task> next);

/// <summary>
/// 響應后
/// </summary>
/// <param name="context">上下文</param>
/// <param name="next">下一個執行委托</param>
/// <returns></returns>
Task OnResponseAsync(ApiResponseContext context, Func<Task> next);

}

結束語

代碼可以寫得很爛,但設計必須高大上,希望WebApiClientCore可以在聲明式客戶端領域繼續引領其它開源庫,同時讓使用它的開發者為之贊嘆。

如果你希望為望WebApiClientCore出力,可以Fork它然后pull request,和我一起完善單元測試,或編寫多語言資源文件,或者加入一些更好的代碼設計。

總結

以上是生活随笔為你收集整理的走进WebApiClientCore的设计的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。