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

How to wrap and replace one of the default components in the ASP.NET 5 configuration

ASP.NET 5 (RC1) 为我们提供了一个全新的配置模型,我们在其中 add/replace 配置了 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 的情况下,ImplementationInstanceImpementationFactory 属性为空,因此无法获取原始对象实例。我们不能在装饰器中注入一个 IServiceProvider 来延迟注册,因为一旦我们在装饰器中请求一个 IHttpContextAccessor ,我们将得到相同的装饰器,这将导致 Whosebug 异常。

有趣的是,使用 MVC 5 和 Web API,这实际上真的 很简单。

如何使用 ASP.NET 5 实现同样的效果?

可以 通过构建 'intermediate' 服务提供商,以 hacky 的方式完成此任务。然后您可以检索原始实现的实例并在创建您自己的实例时使用它:

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

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

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