我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用.Net6中的WebApplication打造最小API

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用.Net6中的WebApplication打造最小API

.net6在preview4时给我们带来了一个新的API:WebApplication,通过这个API我们可以打造更小的轻量级API服务。今天我们来尝试一下如何使用WebApplication设计一个小型API服务系统。

环境准备

  • .NETSDK v6.0.0-preview.5.21355.2
  • Visual 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 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);
        }
    }

最后我们需要将我们的服务接入到WebApplication的map里,怎么做呢?首先我们需要定义一套代理类型用来反射并获取到具体的服务类型。这里为了简单的演示,我只设计包含一个入参和没有入参的情况下:


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);
        }
    }

接着我们创建一个代理工厂用于创建服务的方法委托并创建代理类型实例返回给调用端


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();
        }
    }

最后我们创建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<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;
        }
    }

当然包括我们的自定义容器注入方法:


public class MyServiceDependency
    {
        public static void Register(IServiceCollection services)
        {
            services.AddScoped<IMyService, MyService>();
            services.AddScoped<IMyRepository, MyRepository>();
        }
    }

最后改造我们的program.cs的代码,通过扩展来注入容器和代理委托并最终生成路由-终结点:


await WebApplication.CreateBuilder().RegisterDependencyAndMapDelegate(MyServiceDependency.Register,DynamicPorxyFactory.RegisterDynamicPorxy).RunAsync("http://*:80");

这样这套小型API系统就基本完成了,可以满足日常的依赖注入和独立的业务单元类型编写,最后我们启动并调用一下,可以看到确实否符合我们的预期成功的调用到了应用服务并且仓储也被正确的执行了:

到此这篇关于使用.Net6中的WebApplication打造最小API的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用.Net6中的WebApplication打造最小API

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java Jersey框架开发最佳实践,打造高性能的API应用

Java Jersey框架作为一种轻量级的RESTful Web服务框架,凭借其易于使用、性能优异等特点,在API开发领域备受青睐。为了打造高性能的API应用,掌握Jersey框架的最佳实践至关重要。
Java Jersey框架开发最佳实践,打造高性能的API应用
2024-02-27

JAX-RS RESTful API 设计的最佳实践:打造高效的应用程序

掌握 JAX-RS RESTful API 设计最佳实践至关重要,它们可以帮助创建高效、可维护且用户友好的应用程序。本文探讨了从资源模型到响应处理等各个方面的最佳策略,旨在提升应用程序的性能和用户体验。
JAX-RS RESTful API 设计的最佳实践:打造高效的应用程序
2024-02-28

ASP.NET Core 6最小API中使用日志和DI示例详解

这篇文章主要为大家介绍了ASP.NET Core 6最小API中使用日志和DI示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

PHP 框架中最佳实践:打造健壮而可维护的应用程序

遵循 php 框架的最佳实践可以提高应用程序的健壮性、可维护性和性能。关键做法包括:依赖注入:松散耦合、可测试性提高、维护性更强。单一职责原则:简化代码,提高可测试性和可维护性。单元测试:方便故障诊断,增强应用程序可靠性,提高可重构性。异常
PHP 框架中最佳实践:打造健壮而可维护的应用程序
2024-05-23

可能是全网最详细小程序中使用echarts的教程

在开发微信小程序时,有需求需要使用到柱状图,饼图等图表,下面这篇文章主要给大家介绍了关于小程序中使用echarts的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2022-11-13

在Win7系统开始菜单中设置显示最近使用的项目以便打开应用

在开始菜单中显示最近使用的项目,可以方便用户打开相应的软件,避免重复多次通过计算机依次打开相关软件的文件夹来打开软件,提高工作效率。但是似乎并不是所有的Win7系统安装完成后都会开启这个功能,下面以官方Win7旗舰版系统为例,开启开始菜单最
2023-06-07

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录