.net6在preview4时给我们带来了一个新的api:webapplication,通过这个api我们可以打造更小的轻量级api服务。今天我们来尝试一下如何使用webapplication设计一个小型api服务系统。
环境准备
.netsdk v6.0.0-preview.5.21355.2visual studio 2022 preview首先看看原始版本的webapplication,官方已经提供了样例模板,打开我们的vs2022,选择新建项目选择asp.net core empty,framework选择.net6.0(preview)点击创建,即可生成一个简单的最小代码示例:
如果我们在.csproj里在配置节propertygroup增加使用c#10新语法让自动进行类型推断来隐式的转换成委托,则可以更加精简:
<propertygroup> <targetframework>net6.0</targetframework> <langversion>preview</langversion> </propertygroup>
当然仅仅是这样,是无法用于生产的,毕竟不可能所有的业务单元我们塞进这么一个小小的表达式里。不过借助webapplication我们可以打造一个轻量级的系统,可以满足基本的依赖注入的小型服务。比如通过自定义特性类型,在启动阶段告知系统为哪些服务注入哪些访问路径,形成路由键和终结点。具体代码如下:
首先我们创建一个简易的特性类,只包含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; 科学社会主义理论与实践论文 } }
接着我们按照一般的分层设计一套demo应用层/仓储服务:
public 水手 歌词interface imyrvice { task<myoutput> hello(myinput input); } public interface imyrepository { task<bool> savedata(myoutput data); } public class myrvice : imyrvice { private readonly imyrepository myrepository; public myrvice(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 ta日本国骂sk<bool> savedata(myoutput data) { console.writeline($"保存成功:{data.words}"); return await task.fromresult(true); } }
最后我们需要将我们的服务接入到webapplication的map里,怎么做呢?首先我们需要定义一套代理类型用来反射并获取到具体的服务类型。这里为了简单的演示,我只设计包含一个入参和没有入参的情况下:
public abstract class dynamicporxy { public abstract delegate instance { get; t; } } public class dynamicporxyimpl<tsvc, timpl, tinput, toutput> : dynamicporxy where timpl : class where tinput : class where toutput : class { public override delegate instance { get; t; } public dynamicporxyimpl(methodinfo method) { instance = ([fromrvices] irviceprovider sp, tinput input) => expressiontool.createmethoddelegate<timpl, tinput, toutput>(method)(sp.getrvice(typeof(tsvc)) as timpl, input); } } public class dynamicporxyimpl<tsvc, timpl, toutput> : dynamicporxy where timpl : class where toutput : class { public override delegate instance { get; t; } public dynamicporxyimpl(methodinfo method) { instance = ([fromrvices] irviceprovider sp) => expressiontool.createmethoddelegate<timpl, toutput>(method)(sp.getrvice(typeof(tsvc)) as timpl); } }
接着我们创建一个代理工厂用于创建服务的方法委托并创建代理类型实例返回给调用端
public class dynamicporxyfactory { public static ienumerable<(webrouter, dynamicporxy)> registerdynamicporxy() { foreach (var methodinfo in dependencycontext.default.compilelibraries.where(x => !x.rviceable && x.type != "package") .lect(x => asmblyloadcontext.default.loadfromasmblyname(new asmblyname(x.name))) .lectmany(x => x.gettypes().where(x => !x.isinterface && x.getinterfaces().any()).lectmany(x => x.getmethods().where(y => y.customattributes.any(z => z.attributetype == typeof(webrouter)))))) { var webrouter = methodinfo.getcustomattributes(typeof(webrouter), fal).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; el 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 s洛阳有哪些大学tatic 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 = ex眼部除皱手术pression.convert(mcexpression, typeof(tout)); return expression.lambda<func<tobj, tout>>(reexpression, mparameter).compile(); } }
最后我们创建webapplication的扩展方法来调用代理工厂以及注入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<irvicecollection> registerdependencyaction, func<ienumerable<(webrouter webrouter, dynamicporxy dynamicporxy)>> mapproxybuilder) { webapplicationbuilder.host.configurervices((ctx, rvices) => { registerdependencyaction(rvices); }); var webapplication = webapplicationbuilder.build(); mapproxybuilder().tolist().foreach(item => getwebapplicationmap(item.webrouter.httpmethod, webapplication)(item.webrouter.path, item.dynamicporxy.instance)); return webapplication; } }
当然包括我们的自定义容器注入方法:
public class myrvicedependency { public static void register(irvicecollection rvices) { rvices.addscoped<imyrvice, myrvice>(); rvices.addscoped<imyrepository, myrepository>(); } }
最后改造我们的program.cs的代码,通过扩展来注入容器和代理委托并最终生成路由-终结点:
await webapplication.createbuilder().registerdependencyandmapdelegate(myrvicedependency.register,dynamicporxyfactory.registerdynamicporxy).runasync("http://*:80");
这样这套小型api系统就基本完成了,可以满足日常的依赖注入和独立的业务单元类型编写,最后我们启动并调用一下,可以看到确实否符合我们的预期成功的调用到了应用服务并且仓储也被正确的执行了:
到此这篇关于使用.net6中的webapplication打造最小api的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持www.887551.com。
本文发布于:2023-04-04 12:43:47,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/a84a2d71adff17bae1a3305ce9a0e524.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:使用.Net6中的WebApplication打造最小API.doc
本文 PDF 下载地址:使用.Net6中的WebApplication打造最小API.pdf
留言与评论(共有 0 条评论) |