網(wǎng)站首頁 編程語言 正文
.net6在preview4時給我們帶來了一個新的API:WebApplication,通過這個API我們可以打造更小的輕量級API服務(wù)。今天我們來嘗試一下如何使用WebApplication設(shè)計一個小型API服務(wù)系統(tǒng)。
環(huán)境準(zhǔn)備
- .NETSDK v6.0.0-preview.5.21355.2
- Visual Studio 2022 Preview
首先看看原始版本的WebApplication,官方已經(jīng)提供了樣例模板,打開我們的vs2022,選擇新建項目選擇asp.net core empty,framework選擇.net6.0(preview)點擊創(chuàng)建,即可生成一個簡單的最小代碼示例:
如果我們在.csproj里在配置節(jié)PropertyGroup增加使用C#10新語法讓自動進(jìn)行類型推斷來隱式的轉(zhuǎn)換成委托,則可以更加精簡:
<PropertyGroup> <TargetFramework>net6.0</TargetFramework> <LangVersion>preview</LangVersion> </PropertyGroup>
當(dāng)然僅僅是這樣,是無法用于生產(chǎn)的,畢竟不可能所有的業(yè)務(wù)單元我們?nèi)M(jìn)這么一個小小的表達(dá)式里。不過借助WebApplication我們可以打造一個輕量級的系統(tǒng),可以滿足基本的依賴注入的小型服務(wù)。比如通過自定義特性類型,在啟動階段告知系統(tǒng)為哪些服務(wù)注入哪些訪問路徑,形成路由鍵和終結(jié)點。具體代碼如下:
首先我們創(chuàng)建一個簡易的特性類,只包含httpmethod和path:
[AttributeUsage(AttributeTargets.Method)] public class WebRouter : Attribute { public string path; public HttpMethod httpMethod; public WebRouter(string path) { this.path = path; this.httpMethod = HttpMethod.Post; } public WebRouter(string path, HttpMethod httpMethod) { this.path = path; this.httpMethod = httpMethod; } }
接著我們按照一般的分層設(shè)計一套DEMO應(yīng)用層/倉儲服務(wù):
public interface IMyService { Task<MyOutput> Hello(MyInput input); } public interface IMyRepository { Task<bool> SaveData(MyOutput data); } public class MyService : IMyService { private readonly IMyRepository myRepository; public MyService(IMyRepository myRepository) { this.myRepository = myRepository; } [WebRouter("/", HttpMethod.Post)] public async Task<MyOutput> Hello(MyInput input) { var result = new MyOutput() { Words = $"hello {input.Name ?? "nobody"}" }; await myRepository.SaveData(result); return await Task.FromResult(result); } } public class MyRepository : IMyRepository { public async Task<bool> SaveData(MyOutput data) { Console.WriteLine($"保存成功:{data.Words}"); return await Task.FromResult(true); } }
最后我們需要將我們的服務(wù)接入到WebApplication的map里,怎么做呢?首先我們需要定義一套代理類型用來反射并獲取到具體的服務(wù)類型。這里為了簡單的演示,我只設(shè)計包含一個入?yún)⒑蜎]有入?yún)⒌那闆r下:
public abstract class DynamicPorxy { public abstract Delegate Instance { get; set; } } public class DynamicPorxyImpl<Tsvc, Timpl, Tinput, Toutput> : DynamicPorxy where Timpl : class where Tinput : class where Toutput : class { public override Delegate Instance { get; set; } public DynamicPorxyImpl(MethodInfo method) { Instance = ([FromServices] IServiceProvider sp, Tinput input) => ExpressionTool.CreateMethodDelegate<Timpl, Tinput, Toutput>(method)(sp.GetService(typeof(Tsvc)) as Timpl, input); } } public class DynamicPorxyImpl<Tsvc, Timpl, Toutput> : DynamicPorxy where Timpl : class where Toutput : class { public override Delegate Instance { get; set; } public DynamicPorxyImpl(MethodInfo method) { Instance = ([FromServices] IServiceProvider sp) => ExpressionTool.CreateMethodDelegate<Timpl, Toutput>(method)(sp.GetService(typeof(Tsvc)) as Timpl); } }
接著我們創(chuàng)建一個代理工廠用于創(chuàng)建服務(wù)的方法委托并創(chuàng)建代理類型實例返回給調(diào)用端
public class DynamicPorxyFactory { public static IEnumerable<(WebRouter, DynamicPorxy)> RegisterDynamicPorxy() { foreach (var methodinfo in DependencyContext.Default.CompileLibraries.Where(x => !x.Serviceable && x.Type != "package") .Select(x => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(x.Name))) .SelectMany(x => x.GetTypes().Where(x => !x.IsInterface && x.GetInterfaces().Any()).SelectMany(x => x.GetMethods().Where(y => y.CustomAttributes.Any(z => z.AttributeType == typeof(WebRouter)))))) { var webRouter = methodinfo.GetCustomAttributes(typeof(WebRouter), false).FirstOrDefault() as WebRouter; DynamicPorxy dynamicPorxy; if (methodinfo.GetParameters().Any()) dynamicPorxy = Activator.CreateInstance(typeof(DynamicPorxyImpl<,,,>).MakeGenericType(methodinfo.DeclaringType.GetInterfaces()[0], methodinfo.DeclaringType, methodinfo.GetParameters()[0].ParameterType , methodinfo.ReturnType), new object[] { methodinfo }) as DynamicPorxy; else dynamicPorxy = Activator.CreateInstance(typeof(DynamicPorxyImpl<,,>).MakeGenericType(methodinfo.DeclaringType.GetInterfaces()[0], methodinfo.DeclaringType, methodinfo.ReturnType), new object[] { methodinfo }) as DynamicPorxy; yield return (webRouter, dynamicPorxy); } } }
internal class ExpressionTool { internal static Func<TObj, Tin, Tout> CreateMethodDelegate<TObj, Tin, Tout>(MethodInfo method) { var mParameter = Expression.Parameter(typeof(TObj), "m"); var pParameter = Expression.Parameter(typeof(Tin), "p"); var mcExpression = Expression.Call(mParameter, method, Expression.Convert(pParameter, typeof(Tin))); var reExpression = Expression.Convert(mcExpression, typeof(Tout)); return Expression.Lambda<Func<TObj, Tin, Tout>>(reExpression, mParameter, pParameter).Compile(); } internal static Func<TObj, Tout> CreateMethodDelegate<TObj, Tout>(MethodInfo method) { var mParameter = Expression.Parameter(typeof(TObj), "m"); var mcExpression = Expression.Call(mParameter, method); var reExpression = Expression.Convert(mcExpression, typeof(Tout)); return Expression.Lambda<Func<TObj, Tout>>(reExpression, mParameter).Compile(); } }
最后我們創(chuàng)建WebApplication的擴(kuò)展方法來調(diào)用代理工廠以及注入IOC容器:
public static class WebApplicationBuilderExtension { static Func<string, Delegate, IEndpointConventionBuilder> GetWebApplicationMap(HttpMethod httpMethod, WebApplication webApplication) => (httpMethod) switch { (HttpMethod.Get) => webApplication.MapGet, (HttpMethod.Post) => webApplication.MapPost, (HttpMethod.Put) => webApplication.MapPut, (HttpMethod.Delete) => webApplication.MapDelete, _ => webApplication.MapGet }; public static WebApplication RegisterDependencyAndMapDelegate(this WebApplicationBuilder webApplicationBuilder, Action<IServiceCollection> registerDependencyAction, Func<IEnumerable<(WebRouter webRouter, DynamicPorxy dynamicPorxy)>> mapProxyBuilder) { webApplicationBuilder.Host.ConfigureServices((ctx, services) => { registerDependencyAction(services); }); var webApplication = webApplicationBuilder.Build(); mapProxyBuilder().ToList().ForEach(item => GetWebApplicationMap(item.webRouter.httpMethod, webApplication)(item.webRouter.path, item.dynamicPorxy.Instance)); return webApplication; } }
當(dāng)然包括我們的自定義容器注入方法:
public class MyServiceDependency { public static void Register(IServiceCollection services) { services.AddScoped<IMyService, MyService>(); services.AddScoped<IMyRepository, MyRepository>(); } }
最后改造我們的program.cs的代碼,通過擴(kuò)展來注入容器和代理委托并最終生成路由-終結(jié)點:
await WebApplication.CreateBuilder().RegisterDependencyAndMapDelegate(MyServiceDependency.Register,DynamicPorxyFactory.RegisterDynamicPorxy).RunAsync("http://*:80");
這樣這套小型API系統(tǒng)就基本完成了,可以滿足日常的依賴注入和獨立的業(yè)務(wù)單元類型編寫,最后我們啟動并調(diào)用一下,可以看到確實否符合我們的預(yù)期成功的調(diào)用到了應(yīng)用服務(wù)并且倉儲也被正確的執(zhí)行了:
原文鏈接:https://www.cnblogs.com/gmmy/p/14990077.html
相關(guān)推薦
- 2022-03-20 C++中vector容器的注意事項總結(jié)_C 語言
- 2024-02-29 UNI-APP中點擊事件多重響應(yīng)問題的解決,list列表項item和列表項item中按鈕的點擊事件沖
- 2022-07-02 Python零錢兌換的實現(xiàn)代碼_python
- 2022-09-09 python中字符串的常見操作總結(jié)(一)_python
- 2022-07-12 使用docker搭建Redis-cluster偽集群
- 2022-12-15 ORACLE中%TYPE和%ROWTYPE的使用詳解_oracle
- 2022-02-03 ionic 富文本編輯樣式后,前臺不能回顯樣式
- 2023-04-08 React中useCallback?useMemo到底該怎么用_React
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支