這篇文章給大家分享的是有關ASP.NET Core應用中與第三方IoC/DI框架整合的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、ConfigureServices方法返回的ServiceProvider沒有用!
我們可以通過一個簡單的實例來說明這個問題。我們先定義了如下這個一個MyServiceProvider,它實際上是對另一個ServiceProvider的封裝。簡單起見,我們利用一個字典來保存服務接口與實現(xiàn)類型的映射關系,這個關系可以通過調用Registe方法來注冊。在提供服務實例的GetService方法中,如果提供的服務類型已經(jīng)被注冊,我們會創(chuàng)建并返回對應的實例對象,否則我們將利用封裝的這個ServiceProvider來提供服務。為了確保服務實例能夠被正常回收,如果服務類型實現(xiàn)了IDisposable接口,我們會將它添加到通過字段_disposables表示的集合中。當MyServiceProvider的Dispose方法被調用的時候,提供的這些服務實例的Dispose方法會被調用。
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”的時候,它會調用GetService方法得到這個ServiceScopeFactory對象(采用的服務接口為IServiceScopeFactory),并利用后者創(chuàng)建一個ServiceScope,這個ServiceScope提供的ServiceProvider就是返回的“子ServiceProvider”。
但是對于我們的MyServiceProvider對象來說,當調用它的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);
}
...
}
...
}感謝各位的閱讀!關于“ASP.NET Core應用中與第三方IoC/DI框架整合的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
當前標題:ASP.NETCore應用中與第三方IoC/DI框架整合的示例分析-創(chuàng)新互聯(lián)
當前鏈接:http://chinadenli.net/article24/didoce.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、定制網(wǎng)站、服務器托管、自適應網(wǎng)站、商城網(wǎng)站、域名注冊
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內容