asp.net core-自定义service
asp.net core 结构
先看如下一张图,虚线的黑框是我们的asp.net core程序,外部通过nginx实现反向代理接收http request和response。
内部是一个内置的web服务器Kestrel和web host主机(继承自IHost),web host主机内部是我们的代码,最内部运行的是带有一个个中间件的管道。
下面是启动的流程,创建一个IHostBuilder, 然后配置WebHostBuilder的相关配置(比如监听端口,日志,kestrel或者其他的配置),然后通过Build方法来创建IHost。这时候会调用StartUp的ConfigureService(该方法用于注入服务),然后调用Ihost的Run方法来启动,框架这时会自动调用Startup.Configure方法(该方法用于配置管道的中间件)。
Kestrel的两种使用,kestrel是一个高效的,但功能简单的内置web服务器,所以它一般会跟其他web服务器搭配使用。
IWebHostBuilder 配置
下面通过配置url来展示显示各种方式的运行优先级,下面按优先级从低到高描述下4种配置形式
1. 通过环境变量配置
如图,通过配置LaunchSettings.json中的applicationUrl可以设置ip和端口,这个会自动在下面生成ASPNETCORE_URLS标签。
2. 通过编码配置
3. 通过应用配置
注意图中的urls标签,这个是通过应用配置。另一个ASPNETCORE_URLS是属于环境变量配置,凡是ASPNET开头的配置都是环境变量配置。
4. 通过命令行配置
命令行启动的时候有2种情况,第一种直接在项目根目录通过dotnet run运行,后面配置端口如下图
第二种是通过publish之后生成了dll,如图通过dotnet命令直接运行dll
优先级的意思是,假如同时配置了以上4种,那么最终监听的端口以最后一种命令行的形式,比如9000或者7999.
自定义Service
依赖注入和控制反转相信大家一定不会陌生,任何技术的出现都不是偶然,它必定是为顺应时代而生。随着项目越来越复杂,代码量越来越多,那么代码之间的耦合性就会越多,这个时候IOC容器应运而生。
控制反转是指有一个第三方的容器,它将负责管理你需要的对象,你不再需要创建和管理你想要的对象类以及它的依赖,把创建以及生命周期的管理统统交给他。你只需要专心实现自己的功能。
依赖注入就是把你的类包括它的依赖注入到容器,然后再需要的地方通过某种方式直接拿到(可以是构造函数,接口,特性,setter)。
这一切的目的就是为了实现松耦合,可维护以及可测试。
asp.net core就有这么一个容器IServiceCollection(namespace是DependencyInjection,还有很多其他的依赖注入框架Unity,Autofac,Ninject,它们都是属于.net的,功能比DependencyInjection更加强大)
asp.net core 提供了3种方式注入
// 创建单例 services.AddSingleton(); // 创建瞬时service,每次请求实例,容器都会new一个新的实例 services.AddTransient(); // 作用域,线程单例,在同一个线程里只创建一次。 services.AddScoped();
好了说了这么多,进入正题,如何优雅的实现自定义service
我们可以发现,asp.net core的源码,所有的注入服务基本都是不带参数,并且是通过lambda表达式来实现配置。
这里我们通过1个例子来展示下,我们的需求是注入2个类实现,但是它们的接口是一样得,我们需要调用者通过不同的配置来调用不同的实例。
Interface和实现类就不写了,下面写MessageService的builder类,用于注入2个实现类
public class MessageServiceBuilder { private IServiceCollection serviceCollection; public MessageServiceBuilder(IServiceCollection services) { serviceCollection = services; } public void UseEmail() { ServiceCollection.AddSingleton<IMessageService, EmailService>(); } public void UseSms() { ServiceCollection.AddSingleton<IMessageService, SmsService>(); } }
下面就是核心了,创建一个IServiceCollection的扩展类,然后传入一个参数是MessageServiceBuilder的Action,该Action在Startup中根据所需要的对象,调用特定的方法实现注入,然后执行这个Action。
public static class MessageServiceExtension { public static void AddMessage(this IServiceCollection services, Action<MessageServiceBuilder> configure) { var builder = new MessageServiceBuilder(services); configure(builder); } }
services.AddMessage(builder => builder.UseSms());
lambda让c#成为了最优雅的语言,没有之一。
这也是源码的实现方式,另附上.net core源码,https://github.com/dotnet/core
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构