c# – 如何包装和替换ASP.NET 5配置中的一个默认组件

ASP.NET 5(RC1)为我们提供了一个全新的配置模型,我们在其中添加/替换ServiceDescriptor对象集合的配置.替换默认实现很简单,例如:

services.Add(ServiceDescriptor.Instance<IHttpContextAccessor>(
    new MyHttpContextAccessor()));

但是,我很难找到一种方法来扩展现有注册的额外行为(通过装饰).换句话说,我想用内部使用内置版本的自定义版本替换内置版本.以这种方式扩展框架行为当然很常见.例如:

// How to get the instance here???
IHttpContextAccessor original = 
    services.Last(service => service.ServiceType == typeof(IHttpContextAccessor));

services.Add(ServiceDescriptor.Instance<IHttpContextAccessor>(
    new HttpContextAccessorDecorator(original)));

请注意,使用IHttpContextAccessor只是一个示例,但确实有效地显示了问题. services集合包含ServiceDescriptor对象,对于IHttpContextAccessor,ImplementationInstance和ImpementationFactory属性为空,因此无法获取该原始实例.我们不能将一个IServiceProvider注入装饰器来延迟注册,因为一旦我们在装饰器中请求IHttpContextAccessor,我们就会得到相同的装饰器,这将导致堆栈溢出异常.

有趣的是,使用MVC 5和Web API,这实际上非常简单.

如何在ASP.NET 5中实现相同的功能?

最佳答案 你可以通过建立一个“中间”服务提供商以一种黑客的方式实现这一目标.然后,您可以检索原始实现的实例,并在创建自己的实例时使用它:

var innerSp = services.BuildServiceProvider();
var original = innerSp.GetService<IHttpContextAccessor>();
services.AddInstance<IHttpContextAccessor>(new HttpContextAccessorDecorator(original));

这需要Microsoft.Extensions.DependencyInjection包(而不是Abstractions),因为它使用内部ServiceProvider实现.

当然,这是一个糟糕的解决方案,我同意我们需要更好的东西.

点赞