我正在寻找使用autofac解决Captive Dependency问题的最简洁方法。
我有一个短期课程,将根据LifeTimeScope注册:
public class ShortLived
{
public void DoSomethingUsefull() {}
}
我有一个很长的生活班,将被注册为单一实例。它依赖于ShortLived类:
public class LongLived
{
private readonly Func<ShortLived> _getCurrentShortLived;
public LongLived(Func<ShortLived> getCurrentShortLived)
{
_getCurrentShortLived = getCurrentShortLived;
}
public void DoSomethingWithShortLived()
{
var currentShortLived = _getCurrentShortLived();
currentShortLived.DoSomethingUsefull();
}
}
以下尝试不起作用。它抛出一个Autofac.Core.DependencyResolutionException。
public void CaptiveDependencyTest()
{
var builder = new ContainerBuilder();
builder.RegisterType<LongLived>()
.SingleInstance();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>()))
{
var longLived = scope.Resolve<LongLived>();
longLived.DoSomethingWithShortLived();
}
}
以下工作正常。但我真的希望有一个更好的解决方案,而不是依赖某种静态变量。
private static ILifetimeScope currentLifetimeScope;
public void CaptiveDependencyTest2()
{
var builder = new ContainerBuilder();
builder.Register(c =>
{
Func<ShortLived> shortLivedFacotry = () => currentLifetimeScope.Resolve<ShortLived>();
return new LongLived(shortLivedFacotry);
})
.SingleInstance();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>()))
{
currentLifetimeScope = scope;
var longLived = scope.Resolve<LongLived>();
longLived.DoSomethingWithShortLived();
}
}
一些Backround Infos: 我正在开发一个OWIN托管的ASP.Net WebApi2微服务。当调用其他服务时,我需要从currentOwinContext.Request.User.Identity中读取值并将它们添加到我发送给下一个服务的RequestMessage中。我的LongLived类是DelegatingHandler(即HttpClient&#34; HttpMessageHandler-Pipeline&#34;的一部分),HttpClient需要是.SingleInstance(),因此我不必为每个请求实例化新的HttpClients。 ShortLived类是IOwinContext,它在Owin管道中的LifeTimeScope中注册。
我可以在autofac中注册HttpConfiguration,而不是currentLifeTimeScope的静态变量。然后我可以使用httpConfig.DependencyResolver.GetRequestLifetimeScope()获取currentLifeTimeScope;我还没有测试过这种方法。我仍然希望找到更清洁的东西。
答案 0 :(得分:1)
如果在容器中注册了类型T,Autofac将自动解析对Func的依赖关系作为通过容器创建T实例的工厂,请查找有关委托工厂的更多信息
注册您的ShortLived课程如下所示,现在一切正常。
public void CaptiveDependencyTest()
{
var builder = new ContainerBuilder();
builder.RegisterType<ShortLived>()
.SingleInstance();
builder.RegisterType<LongLived>()
.SingleInstance();
var container = builder.Build();
//using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>()))
//{
var longLived = container.Resolve<LongLived>();
longLived.DoSomethingWithShortLived();
//}
}
你可以直接从容器中解决使用不再需要但最终选择是你的
答案 1 :(得分:0)
在 ASP.NET Core 中,HttpContext
类提供属性public IServiceProvider RequestServices { get; set; }
。即使您仅具有对根生存期作用域的引用,这也可用于解决请求生存期作用域的依赖性。诀窍是要记住ILifetimeScope
可以从任何IComponentContext
解析。可以将这种行为封装在以下扩展方法中。
public static ILifetimeScope GetLifetimeScope(this HttpContext httpContext)
{
return httpContext.RequestServices.GetService(typeof(ILifetimeScope)) as ILifetimeScope;
}
使用给定的IComponentContext
实例,现在可以通过以下代码轻松进入“每个请求”生存期范围。
ctx => {
var requestScope = ctx.Resolve<IHttpContextAccessor>().HttpContext.GetLifetimeScope();
var shortLived = requestScope.Resolve<ShortLived>();
}
在传统的 ASP.NET 中,有一个“依赖关系解析器”,而不是“服务提供者”。
例如GlobalConfiguration.Configuration.DependencyResolver =
在此处集成autofac
解决ILifetimeScope
有点麻烦。
public static ILifetimeScope GetLifetimeScope(this HttpContext httpContext)
{
var requestMessage = httpContext.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
return requestMessage?.GetDependencyScope().GetService(typeof(ILifetimeScope)) as ILifetimeScope;
}
var requestScope = HttpContext.Current.GetLifetimeScope();
var shortLived = requestScope.Resolve<ShortLived>();