欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ASP.NET Core應用中與第三方IoC/DI框架的整合

 更新時間:2017年04月11日 11:39:43   作者:蔣金楠  
ASP.NET Core應用中,針對第三方DI框架的整合可以通過在定義Startup類型的ConfigureServices方法返回一個ServiceProvider來實現(xiàn)。但是并不是那么容易的,下面通過實例給大家分享一下

一、ConfigureServices方法返回的ServiceProvider沒有用!

我們可以通過一個簡單的實例來說明這個問題。我們先定義了如下這個一個MyServiceProvider,它實際上是對另一個ServiceProvider的封裝。簡單起見,我們利用一個字典來保存服務接口與實現(xiàn)類型的映射關系,這個關系可以通過調(diào)用Registe方法來注冊。在提供服務實例的GetService方法中,如果提供的服務類型已經(jīng)被注冊,我們會創(chuàng)建并返回對應的實例對象,否則我們將利用封裝的這個ServiceProvider來提供服務。為了確保服務實例能夠被正?;厥?,如果服務類型實現(xiàn)了IDisposable接口,我們會將它添加到通過字段_disposables表示的集合中。當MyServiceProvider的Dispose方法被調(diào)用的時候,提供的這些服務實例的Dispose方法會被調(diào)用。

 public class MyServiceProvider : IServiceProvider, IDisposable
 {
 private IServiceProvider _innerServiceProvider;
 private Dictionary<Type, Type> _services;
 private List<IDisposable> _disposables;
 
 public MyServiceProvider(IServiceProvider innerServiceProvider)
 {
 _innerServiceProvider = innerServiceProvider;
 this._services = new Dictionary<Type, Type>();
 _disposables = new List<IDisposable>();
 }
 
 
 public MyServiceProvider Register<TFrom, TTo>() where TTo: TFrom, new()
 {
 _services[typeof(TFrom)] = typeof(TTo);
 return this;
 }
 
 public object GetService(Type serviceType)
 {
 Type implementation;
 if (_services.TryGetValue(serviceType, out implementation))
 {
 object service = Activator.CreateInstance(implementation);
 IDisposable disposbale = service as IDisposable;
 if (null != disposbale)
 {
  _disposables.Add(disposbale);
 }
 return service;
 }
 return _innerServiceProvider.GetService(serviceType);
 }
 
 public void Dispose()
 {
 (_innerServiceProvider as IDisposable)?.Dispose();
 foreach (var it in _disposables)
 {
 it.Dispose();
 }
 _disposables.Clear();
 }
 }

我們按照如下的方式在一個ASP.NET Core應用中使用MyServiceProvider。如下面的代碼片斷中,在注冊的Starup類型中,我們讓ConfigureServices方法返回一個MyServiceProvider對象。服務接口IFoobar和實現(xiàn)類型Foobar之間的映射注冊在這個MyServiceProvider對象上。在處理請求的時候,我們利用當前HttpContext對象的RequestServices屬性得到為請求處理提供服務的ServiceProvider,并試圖利用它得到注冊的IFoobar服務。

 public class Program
 {
 public static void Main(string[] args)
 {
 new WebHostBuilder()
 .UseKestrel()
 .UseStartup<Startup>()
 .Build()
 .Run();
 }
 }
 
 public class Startup
 {
 public IServiceProvider ConfigureServices(IServiceCollection services)
 {
 return new MyServiceProvider(services.BuildServiceProvider())
 .Register<IFoobar, Foobar>();
 }
 
 public void Configure(IApplicationBuilder app)
 {
 app.UseDeveloperExceptionPage()
 .Run(async context => await context.Response.WriteAsync(context.RequestServices.GetRequiredService<IFoobar>().GetType().Name));
 }
 }
 public interface IFoobar { }
 public class Foobar : IFoobar { }

整個應用就這樣簡單,貌似也沒有什么問題,但是我們啟動應用并利用瀏覽器訪問該應用是就會出現(xiàn)如下所示的錯誤。錯誤信息表示服務接口IFoobar尚未被注冊。

二、原因何在?

我們明明在返回的ServiceProvider注冊了IFoobar和Foobar之間的映射關系,為什么RequestServices返回的ServiceProvider說該服務尚未被注冊呢?唯一的解釋就是ConfigureServices方法返回的ServiceProvider與HttpContext的RequestServices返回的ServiceProvider根本就不是同一個。實際上它們本來就不是同一個對象。

ConfigureServices方法返回的ServiceProvider將會作為WebHost的ServiceProvider,對于每次接收的請求,WebHost會根據(jù)這個ServiceProvider創(chuàng)建一個新的ServiceProvider來作為HttpContext的RequestServices屬性,這兩個ServiceProvider具有父子管理。照例說,如果RequestServices返回的ServiceProvider是根據(jù)ConfigureServices方法返回的ServiceProvider創(chuàng)建的,那么它也應該能夠識別注冊的服務類型IFoobar,那么為什么依然會出現(xiàn)錯誤呢?

要了解這個問題,就需要知道這個所謂的“子ServiceProvider”是如何被創(chuàng)建出來的,這其中涉及到ServiceScope的概念。簡單來說,ServiceScope是對一個ServiceProvider的封裝,前者決定后者的生命周期。ServiceScope由ServiceScopeFactory創(chuàng)建,后者以一個服務的形式注冊到“父ServiceProvider”上面。當“父ServiceProvider”需要創(chuàng)建“子ServiceProvider”的時候,它會調(diào)用GetService方法得到這個ServiceScopeFactory對象(采用的服務接口為IServiceScopeFactory),并利用后者創(chuàng)建一個ServiceScope,這個ServiceScope提供的ServiceProvider就是返回的“子ServiceProvider”。

但是對于我們的MyServiceProvider對象來說,當調(diào)用它的GetService方法試圖獲取ServiceScopeFactory對象的時候,獲取的實際上是被封裝的那個SerivceProvider關聯(lián)的ServiceScopeFactory,那么很自然創(chuàng)建的“子ServiceProvider”也與MyServiceProvider沒有什么關系。

三、如何解決這個問題?

既然我們知道了問題的根源,我們自然就有了解決方案。解決方案并不復雜,我們只需要MyServiceProvider的GetService方法返回反映其自身服務注冊相關的ServiceScopeFactory。為此我們定義了如下一個ServiceScope和對應的ServiceScopeFactory。

 internal class ServiceScope : IServiceScope
 {
 private MyServiceProvider _serviceProvider;
 
 public ServiceScope(IServiceScope innserServiceScope, Dictionary<Type, Type> services)
 {
 _serviceProvider = new MyServiceProvider(innserServiceScope.ServiceProvider, services);
 }
 public IServiceProvider ServiceProvider
 {
 get { return _serviceProvider; }
 }
 
 public void Dispose()
 {
 _serviceProvider.Dispose();
 }
 }
 
 internal class ServiceScopeFactory : IServiceScopeFactory
 {
 private IServiceScopeFactory _innerServiceFactory;
 private Dictionary<Type, Type> _services;
 
 public ServiceScopeFactory(IServiceScopeFactory innerServiceFactory, Dictionary<Type, Type> services)
 {
 _innerServiceFactory = innerServiceFactory;
 _services = services;
 }
 public IServiceScope CreateScope()
 {
 return new ServiceScope(_innerServiceFactory.CreateScope(), _services);
 }
 }

除此之外,我們?yōu)镸yServiceProvider添加了一個構造函數(shù),GetService方法也針對IServiceScopeFactory添加了相應的代碼。

 public class MyServiceProvider : IServiceProvider, IDisposable
{
 public MyServiceProvider(IServiceProvider innerServiceProvider, Dictionary<Type, Type> services)
 {
 _innerServiceProvider = innerServiceProvider;
 _services = services;
 _disposables = new List<IDisposable>();
 }
 
 public object GetService(Type serviceType)
 {
 if (serviceType == typeof(IServiceScopeFactory))
 {
 IServiceScopeFactory innerServiceScopeFactory = _innerServiceProvider.GetRequiredService<IServiceScopeFactory>();
 return new ServiceScopeFactory(innerServiceScopeFactory, _services);
 }
 ... 
 }
 ...
 }

以上分享,希望能對需要解決這樣問題的朋友有所幫助!

相關文章

  • 未在本地計算機上注冊“microsoft.ACE.oledb.12.0”提供程序報錯的解決辦法

    未在本地計算機上注冊“microsoft.ACE.oledb.12.0”提供程序報錯的解決辦法

    這篇文章主要給大家介紹了關于未在本地計算機上注冊“microsoft.ACE.oledb.12.0”提供程序報錯的完美解決辦法,需要的朋友可以參考下
    2019-03-03
  • .net core下配置訪問數(shù)據(jù)庫操作

    .net core下配置訪問數(shù)據(jù)庫操作

    本篇文章給大家詳細分享了在.net core下配置訪問數(shù)據(jù)庫的相關操作過程以及代碼實現(xiàn)過程,有興趣的朋友參考下。
    2018-03-03
  • MVC5 + EF6 + Bootstrap3 (11) 實現(xiàn)排序、搜索、分頁

    MVC5 + EF6 + Bootstrap3 (11) 實現(xiàn)排序、搜索、分頁

    本篇文章主要介紹了MVC5 + EF6 + Bootstrap3 (11) 實現(xiàn)排序、搜索、分頁,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考
    2016-12-12
  • asp.net core集成MongoDB的完整步驟

    asp.net core集成MongoDB的完整步驟

    前兩天在學習MongoDB相關的知識,做了個小Demo,下面這篇文章主要給大家介紹了關于asp.net core集成MongoDB的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-10-10
  • 正則方式的自動小偷抓網(wǎng)程序

    正則方式的自動小偷抓網(wǎng)程序

    公司里面有許多數(shù)據(jù)沒人去錄入,做一個抓取網(wǎng)頁的程序,以前做CMS系統(tǒng)的時候涉及過,不過這次的處理HTML上和以前做了些區(qū)別
    2011-11-11
  • .net MVC使用Session驗證用戶登錄(4)

    .net MVC使用Session驗證用戶登錄(4)

    這篇文章主要為大家詳細介紹了.net MVC使用Session驗證用戶登錄的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • asp.net 多數(shù)據(jù)庫支持的思考

    asp.net 多數(shù)據(jù)庫支持的思考

    最近一直在思考如何做一個支持多種數(shù)據(jù)庫的程序,打印了很多的資料,在.NET 2.0中,新增加了DbProviderFactory抽象工廠類,讓數(shù)據(jù)層基類可以實現(xiàn)多種數(shù)據(jù)庫,但在數(shù)據(jù)訪問層中的參數(shù)部分我覺得是個麻煩。
    2009-07-07
  • .Net實現(xiàn)延遲隊列

    .Net實現(xiàn)延遲隊列

    這篇文章介紹了.Net實現(xiàn)延遲隊列的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • asp.net頁面master頁面與ascx用戶控件傳值的問題

    asp.net頁面master頁面與ascx用戶控件傳值的問題

    aspx 頁面,master頁面與ascx用戶控件傳值的問題
    2010-03-03
  • 解決ASP.NET?Core中使用漏桶算法限流的問題

    解決ASP.NET?Core中使用漏桶算法限流的問題

    漏桶算法是限流的四大主流算法之一,其應用場景各種資料中介紹的不多,一般都是說應用在網(wǎng)絡流量控制中,今天通過本文給大家介紹ASP.NET?Core中使用漏桶算法限流的問題,感興趣的朋友跟隨小編一起看看吧
    2021-12-12

最新評論