如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?

这篇具有很好参考价值的文章主要介绍了如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们知道整个ASP.NET Core建立在以ServiceCollection/ServiceProvider为核心的DI框架上,它甚至提供了扩展点使我们可以与第三方DI框架进行整合。对此比较了解的读者朋友应该很清楚,针对第三方DI框架的整合可以通过在定义Startup类型的ConfigureServices方法返回一个ServiceProvider来实现。但是真的有这么简单吗?

一、ConfigureServices方法返回的ServiceProvider貌似没有用!?

我们可以通过一个简单的实例来说明这个问题。我们先定义了如下这个一个MyServiceProvider,它实际上是对另一个ServiceProvider的封装。简单起见,我们利用一个字典来保存服务接口与实现类型的映射关系,这个关系可以通过调用Registe方法来注册。在提供服务实例的GetService方法中,如果提供的服务类型已经被注册,我们会创建并返回对应的实例对象,否则我们将利用封装的这个ServiceProvider来提供服务。为了确保服务实例能够被正常回收,如果服务类型实现了IDisposable接口,我们会将它添加到通过字段_disposables表示的集合中。当MyServiceProvider的Dispose方法被调用的时候,提供的这些服务实例的Dispose方法会被调用。

   1: public class MyServiceProvider : IServiceProvider, IDisposable
   2: {
   3:     private IServiceProvider        _innerServiceProvider;
   4:     private Dictionary<Type, Type>  _services;
   5:     private List<IDisposable>       _disposables;
   6:  
   7:     public MyServiceProvider(IServiceProvider innerServiceProvider)
   8:     {
   9:         _innerServiceProvider  = innerServiceProvider;
  10:         this._services         = new Dictionary<Type, Type>();
  11:         _disposables           = new List<IDisposable>();
  12:     }
  13:  
  14:  
  15:     public MyServiceProvider Register<TFrom, TTo>() where TTo: TFrom, new()
  16:     {
  17:         _services[typeof(TFrom)] = typeof(TTo);
  18:         return this;
  19:     }
  20:  
  21:     public object GetService(Type serviceType)
  22:     {
  23:         Type implementation;
  24:         if (_services.TryGetValue(serviceType, out implementation))
  25:         {
  26:             object service = Activator.CreateInstance(implementation);
  27:             IDisposable disposbale = service as IDisposable;
  28:             if (null != disposbale)
  29:             {
  30:                 _disposables.Add(disposbale);
  31:             }
  32:             return service;
  33:         }
  34:         return _innerServiceProvider.GetService(serviceType);
  35:     }
  36:  
  37:     public void Dispose()
  38:     {
  39:         (_innerServiceProvider as IDisposable)?.Dispose();
  40:         foreach (var it in _disposables)
  41:         {
  42:             it.Dispose();
  43:         }
  44:         _disposables.Clear();
  45:     }
  46: }

我们按照如下的方式在一个ASP.NET Core应用中使用MyServiceProvider。如下面的代码片断中,在注册的Starup类型中,我们让ConfigureServices方法返回一个MyServiceProvider对象。服务接口IFoobar和实现类型Foobar之间的映射注册在这个MyServiceProvider对象上。在处理请求的时候,我们利用当前HttpContext对象的RequestServices属性得到为请求处理提供服务的ServiceProvider,并试图利用它得到注册的IFoobar服务。

   1: public class Program
   2: {
   3:     public static void Main(string[] args)
   4:     {
   5:         new WebHostBuilder()
   6:             .UseKestrel()
   7:             .UseStartup<Startup>()
   8:             .Build()
   9:             .Run();
  10:     }
  11: }
  12:  
  13: public class Startup
  14: {
  15:     public IServiceProvider ConfigureServices(IServiceCollection services)
  16:     {
  17:         return new MyServiceProvider(services.BuildServiceProvider())
  18:             .Register<IFoobar, Foobar>();
  19:     }
  20:  
  21:     public void Configure(IApplicationBuilder app)
  22:     {
  23:         app.UseDeveloperExceptionPage()
  24:             .Run(async context => await context.Response.WriteAsync(context.RequestServices.GetRequiredService<IFoobar>().GetType().Name));
  25:     }
  26: }
  27: public interface IFoobar { }
  28: public class Foobar : IFoobar { }

整个应用就这样简单,貌似也没有什么问题,但是我们启动应用并利用浏览器访问该应用是就会出现如下所示的错误。错误信息表示服务接口IFoobar尚未被注册。

如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?

二、原因何在?

我们明明在返回的ServiceProvider注册了IFoobar和Foobar之间的映射关系,为什么RequestServices返回的ServiceProvider说该服务尚未被注册呢?唯一的解释就是ConfigureServices方法返回的ServiceProvider与HttpContext的RequestServices返回的ServiceProvider根本就不是同一个。实际上它们本来就不是同一个对象。

我在前面中曾经谈到过:ConfigureServices方法返回的ServiceProvider将会作为WebHost的ServiceProvider,对于每次接收的请求,WebHost会根据这个ServiceProvider创建一个新的ServiceProvider来作为HttpContext的RequestServices属性,这两个ServiceProvider具有父子管理。照例说,如果RequestServices返回的ServiceProvider是根据ConfigureServices方法返回的ServiceProvider创建的,那么它也应该能够识别注册的服务类型IFoobar,那么为什么依然会出现错误呢?

要了解这个问题,就需要知道这个所谓的“子ServiceProvider”是如何被创建出来的,这其中涉及到ServiceScope的概念。简单来说,ServiceScope是对一个ServiceProvider的封装,前者决定后者的生命周期。ServiceScope由ServiceScopeFactory创建,后者以一个服务的形式注册到“父ServiceProvider”上面。当“父ServiceProvider”需要创建“子ServiceProvider”的时候,它会调用GetService方法得到这个ServiceScopeFactory对象(采用的服务接口为IServiceScopeFactory),并利用后者创建一个ServiceScope,这个ServiceScope提供的ServiceProvider就是返回的“子ServiceProvider”。

但是对于我们的MyServiceProvider对象来说,当调用它的GetService方法试图获取ServiceScopeFactory对象的时候,获取的实际上是被封装的那个SerivceProvider关联的ServiceScopeFactory,那么很自然创建的“子ServiceProvider”也与MyServiceProvider没有什么关系。

三、如何解决这个问题?

既然我们知道了问题的根源,我们自然就有了解决方案。解决方案并不复杂,我们只需要MyServiceProvider的GetService方法返回反映其自身服务注册相关的ServiceScopeFactory。为此我们定义了如下一个ServiceScope和对应的ServiceScopeFactory。

   1: internal class ServiceScope : IServiceScope
   2: {
   3:     private MyServiceProvider _serviceProvider;
   4:  
   5:     public ServiceScope(IServiceScope innserServiceScope, Dictionary<Type, Type> services)
   6:     {
   7:         _serviceProvider = new MyServiceProvider(innserServiceScope.ServiceProvider, services);
   8:     }
   9:     public IServiceProvider ServiceProvider
  10:     {
  11:         get { return _serviceProvider; }
  12:     }
  13:  
  14:     public void Dispose()
  15:     {
  16:         _serviceProvider.Dispose();
  17:     }
  18: }
  19:  
  20: internal class ServiceScopeFactory : IServiceScopeFactory
  21: {
  22:     private IServiceScopeFactory _innerServiceFactory;
  23:     private Dictionary<Type, Type> _services;
  24:  
  25:     public ServiceScopeFactory(IServiceScopeFactory innerServiceFactory, Dictionary<Type, Type> services)
  26:     {
  27:         _innerServiceFactory = innerServiceFactory;
  28:         _services = services;
  29:     }
  30:     public IServiceScope CreateScope()
  31:     {
  32:         return new ServiceScope(_innerServiceFactory.CreateScope(), _services);
  33:     }
  34: }

除此之外,我们为MyServiceProvider添加了一个构造函数,GetService方法也针对IServiceScopeFactory添加了相应的代码。文章来源地址https://www.toymoban.com/news/detail-491857.html

   1: public class MyServiceProvider : IServiceProvider, IDisposable
   2: {
   3:     public MyServiceProvider(IServiceProvider innerServiceProvider, Dictionary<Type, Type> services)
   4:     {
   5:         _innerServiceProvider = innerServiceProvider;
   6:         _services = services;
   7:         _disposables = new List<IDisposable>();
   8:     }
   9:  
  10:     public object GetService(Type serviceType)
  11:     {
  12:         if (serviceType == typeof(IServiceScopeFactory))
  13:         {
  14:             IServiceScopeFactory innerServiceScopeFactory = _innerServiceProvider.GetRequiredService<IServiceScopeFactory>();
  15:             return new ServiceScopeFactory(innerServiceScopeFactory, _services);
  16:         }
  17:         ...        
  18:     }
  19:     ...
  20: }

到了这里,关于如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ASP.NET Core 基础知识】--最佳实践和进阶主题--设计模式在ASP.NET Core中的应用

    一、设计模式概述 1.1 什么是设计模式 设计模式是在软件设计过程中反复出现的、经过验证的、可重用的解决问题的方法。它们是针对特定问题的通用解决方案,提供了一种在软件开发中可靠的指导和标准化方法。设计模式通常描述了一种在特定情景下的解决方案,包括了问

    2024年02月21日
    浏览(42)
  • ASP.NET Core实时库SignalR简单应用

    SignalR 是用于构建需要实时用户交互或实时数据更新的Web 应用程序的一个开放源代码.NET 库。不仅仅用在Web应用中,后面会讲到它的应用范围。它简化了简化了构建实时应用程序的过程,包括 ASP.NET Server 库和 JavaScript Client 库,以便管理Client与Server连接并将内容更新推送给Cl

    2024年02月11日
    浏览(61)
  • ASP.NET Core Web应用程序项目部署流程

    目录 一、准备ASP.NET Core应用程序部署文件 二、环境配置 三、测试 ASP.NET Core Web 应用程序 四、部署后访问失败问题 以下部署流程都是基于Windows服务器环境下进行的。 一、准备ASP.NET Core应用程序部署文件 使用 Visual Studio 开发工具创建 ASP.NET Core 的Web应用程序,利用VS工具发布

    2024年02月05日
    浏览(49)
  • 使用任务计划开机启动ASP.NET Core应用程序

    ASP.NET Core应用程序现在是一个控制台应用程序,在Windows上直接双击启动,但如果想让开发完成的ASP.NET Core应用程序开机启动,可以将ASP.NET Core应用程序修改成Windows服务运行,但这需要额外添加代码,也可以使用IIS来托管ASP.NET Core应用程序,但可能需要安装一些支持IIS的组件

    2024年02月08日
    浏览(46)
  • 如何在没有第三方.NET库源码的情况,调试第三库代码?

    大家好,我是沙漠尽头的狼。 本方首发于Dotnet9,介绍使用dnSpy调试第三方.NET库源码,行文目录: 安装dnSpy 编写示例程序 调试示例程序 调试.NET库原生方法 总结 dnSpy是一款功能强大的.NET程序反编译工具,可以对.NET程序进行反编译,代替库文档的功能,代码丢失或者损坏可直

    2024年02月08日
    浏览(48)
  • 模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案

    免责声明 使用者本人对于传播和利用本公众号提供的信息所造成的任何直接或间接的后果和损失负全部责任。公众号及作者对于这些后果不承担任何责任。如果造成后果,请自行承担责任。谢谢! 大家好,我是沙漠尽头的狼。 本文首发于Dotnet9,结合前面两篇(如何在没有第

    2024年02月08日
    浏览(29)
  • Asp.net core Webapi 如何执行定时任务?

    在计算机系统中,定时执行一些后台任务是很常见的场景,比如定时发送邮件、备份数据等等。 那么,.NET 技术如何通过编程灵活地实现项目里复杂的自定义任务呢? 如果是 Windows 生态,通常来说,可以有这些方式: 编写一个程序,通过 Windows 内置的任务计划来定时执行。

    2024年02月04日
    浏览(30)
  • 单元测试必备:Asp.Net Core代码覆盖率实战,打造可靠应用 !

    在前几章我们深度讲解了单元测试和集成测试的基础知识,这一章我们来讲解一下 代码覆盖率 ,代码覆盖率是单元测试运行的 度量值 ,覆盖率通常以百分比表示,用于衡量代码被测试覆盖的程度,帮助开发人员评估测试用例的质量和代码的健壮性。常见的覆盖率包括语句覆盖

    2024年04月23日
    浏览(30)
  • 如何在 ASP.NET Core 配置请求超时中间件

    本文参考官方文档,使用Asp.net core 8.0 的最小API 模板项目,配置超时中间件。 超时中间件可用于所有类型的ASP.NET Core应用:最小 API、带控制器的 Web API、MVC 和 Razor Pages。请求超时的属性位于命名空间 Microsoft.AspNetCore.Http.Timeouts 中。 需要注意的是,当应用在调试模式下运行时

    2024年01月20日
    浏览(43)
  • asp.net core webapi如何执行周期性任务

    新建asp.net core webapi项目,使用Nuget搜索安装Quartz包。 注意:定时执行时间格式,参考连接:https://www.cnblogs.com/wudequn/p/8506938.html 在IIS中找到这个站点所用的程序池,点击“高级设置…” 在打开的列表中更改以下设置: 回收——固定时间间隔(分钟) 改为 0 ——虚拟/专用内存

    2024年02月13日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包