一、ConfigureServices方法返回的ServiceProvider没有用!
我们可以通过一个简单的实例来说明这个问题。我们先定义了如下这个一个MyServiceProvider,它实际上是对另一个ServiceProvider的封装。简单起见,我们利用一个字典来保存服务接口与实现类型的映射关系,这个关系可以通过调用Registe方法来注册。在提供服务实例的GetService方法中,如果提供的服务类型已经被注册,我们会创建并返回对应的实例对象,否则我们将利用封装的这个ServiceProvider来提供服务。为了确保服务实例能够被正常回收,如果服务类型实现了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)"htmlcode">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 { }整个应用就这样简单,貌似也没有什么问题,但是我们启动应用并利用浏览器访问该应用是就会出现如下所示的错误。错误信息表示服务接口IFoobar尚未被注册。
二、原因何在?
我们明明在返回的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。
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); } }除此之外,我们为MyServiceProvider添加了一个构造函数,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); } ... } ... }以上分享,希望能对需要解决这样问题的朋友有所帮助!
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 第五街的士高《印度激情版》3CD [WAV+CUE][2.4G]
- 三国志8重制版哪个武将智力高 三国志8重制版智力武将排行一览
- 三国志8重制版哪个武将好 三国志8重制版武将排行一览
- 三国志8重制版武将图像怎么保存 三国志8重制版武将图像设置方法
- 何方.1990-我不是那种人【林杰唱片】【WAV+CUE】
- 张惠妹.1999-妹力新世纪2CD【丰华】【WAV+CUE】
- 邓丽欣.2006-FANTASY【金牌大风】【WAV+CUE】
- 饭制《黑神话》蜘蛛四妹手办
- 《燕云十六声》回应跑路:年内公测版本完成95%
- 网友发现国内版《双城之战》第二季有删减:亲亲环节没了!
- 邓丽君2024-《漫步人生路》头版限量编号MQA-UHQCD[WAV+CUE]
- SergeProkofievplaysProkofiev[Dutton][FLAC+CUE]
- 永恒英文金曲精选4《TheBestOfEverlastingFavouritesVol.4》[WAV+CUE]
- 群星《国风超有戏 第9期》[320K/MP3][13.63MB]
- 群星《国风超有戏 第9期》[FLAC/分轨][72.56MB]