我是Autofac
的新手,我非常喜欢它的终身范围功能,但我遇到了问题。
我需要在InstancePerRequest
的基础上使用一个对象的实例,该对象来自一个对.Net MVC Web没有反抗意见的程序集中的单例
我尝试了this帖子的建议,但它没有用。我得到了这个例外:
没有标记匹配的范围' AutofacWebRequest'是可见的 请求实例的范围。
在Singleton中获取/使用InstancePerRequest对象的正确方法是什么?
更新 我想澄清一下,考虑到特拉维斯的回答,我们不想在单身人士中持有captive dependency InstancePerRequest项目。我们想在每次使用时请求该项目。我们进行了分析,将单例设置为InstancePerRequest比将每次使用InstancePerRequest项请求容器更昂贵。 这被认为是一种不好的做法吗?在请求级别拥有您需要访问的某些内容并让Singleton使用它们是相当普遍的。
答案 0 :(得分:3)
不要在单件中获取每个请求项。这会产生captive dependency,这是个坏消息。将单例切换为每个请求。
答案 1 :(得分:0)
鉴于Dzyann的更新
对我来说,这听起来像每个请求实例需要一个实例工厂。这样,Factory Func可以是单例,并且可以避免Captive Dependency。 代码看起来像这样。
public class MySingleton
{
private readonly Func<IMyInstancePerRequestType> _instanceFactory;
public MySingleton(Func<IMyInstancePerRequestType> instanceFactory)
{
_instanceFactory = instanceFactory;
}
public void DoStuff()
{
var myService = _instanceFactory();
myService.DoStuff();
}
}
Autofac会隐式为您创建工厂方法。 因此不需要额外的注册。
请务必查看http://docs.autofac.org/en/latest/resolve/relationships.html
关于'AutofacWebRequest'错误,您需要使用AutofacMvc或AutoFacWebAPI nuget包并在启动期间使用Owin扩展方法(给定您使用owin)注册这将创建'AutofacWebRequest'生命受害者。
在startup.cs中它会像
app.UseAutofacMiddleware( iocContainer );
app.UseAutofacWebApi( configuration );
你指的是一篇文章。在那里我们有
builder.Register<Func<IDataStore>>(c =>
{
var context = c.Resolve<IComponentContext>();
return context.Resolve<IDataStore>;
});
.InstancePerHttpRequest()可以在那里添加。
答案 2 :(得分:0)
感谢大家的回答和评论,事实证明解决方案非常简单。 这是我最终拥有的文件结构:
非网络汇编
public IPerRequestDependencyResolver
{
T Get<T>() where T : class;
}
public interface IPerRequestObject
{
void DoSomething();
}
public class PerRequestObject: IPerRequestObject
{
public void DoSomething()
{}
}
public interface IMySingletonPerRequestWrapper
{
DoSomethingOnPerRequestBasis();
}
public class MySingletonPerRequestWrapper: IMySingletonPerRequestWrapper
{
private IPerRequestDependencyResolver perRequestDependencyResolver;
public PerRequestWrapper(IPerRequestDependencyResolver perRequestDependencyResolver)
{
this.perRequestDependencyResolver = perRequestDependencyResolver;
}
public void DoSomethingOnPerRequestBasis()
{
this.perRequestDependencyResolver.Get<IPerRequestObject>().DoSomething();
}
}
public interface IMySingletonBussinesObject
{
void DoSomething();
}
public class MySingletonBussinessObject: IMySingletonBussinesObject
{
private IMySingletonPerRequestWrapper mysingletonPerRequestWrapper;
public MySingletonBussinessObject(IMySingletonPerRequestWrapper mysingletonPerRequestWrapper)
{
this.mysingletonPerRequestWrapper = mysingletonPerRequestWrapper;
}
public void DoSomething()
{
this.mysingletonPerRequestWrapper.DoSomethingOnPerRequestBasis();
}
}
MVC Web程序集
public class PerRequestDependencyResolver : IPerRequestDependencyResolver
{
public T Get<T>() where T : class
{
return DependencyResolver.Current.GetService<T>();
}
}
MySingletonPerRequestWrapper
,MySingletonBussinessObject
,PerRequestDependencyResolver
在 Autofac 中配置为.SingleInstance()
,而PerRequestObject
配置为`InstancePerRequest()
我创建了MySingletonPerRequestWrapper
,而不是直接使用PerRequestDependencyResolver
中的MySingletonBussinessObject
,因为我想确保使用PerRequestObject
的任何人都能正确使用并且没有人工制作的实例是错误的。
我宁愿使用 Autofac 来保留我的所有实例,而不是将我的实例保留在HttpRequest
并从那里使用它(使用包装器),我觉得这更灵活。
更新网络广告
这是使用此技术与WebApi的更新。我没有自己完成实施,我们在我的小组讨论过它,而且一位朋友实施了它。我将解释他采取的方法。
为了清晰起见,我简化了逻辑和类,你可以改变你需要的任何东西。 在我们的系统中,我们配置了Autofac,因此您可以在静态类中注入实例。你可以把它改成更适合你的东西。
首先是一些帮助,扩展方法来简化。
public static class Extensions
{
private const string dependencyScopeKey = "Resolver.Unique.key";
public static IExecutionContext ExecutionContext { get; set; }
public static IDependencyScope Current(this IDependencyResolver dependencyResolver)
{
return ExecutionContext.GetObject<IDependencyScope>(dependencyScopeKey);
}
public static void SetCurrentDependencyScope(this HttpRequestMessage request)
{
ExecutionContext.SetObject(dependencyScopeKey, request.GetDependencyScope());
}
}
public class WebExecutionContext : IExecutionContext
{
public T GetObject <T>(string key)
{
var result = HttpContext.Current.Items[key];
return result != null ? (T) result : default(T);
}
public void SetObject(string key, object val)
{
if (HttpContext.Current.Items.Contains(key))
HttpContext.Current.Items.Remove(key);
HttpContext.Current.Items.Add(key, val);
}
}
然后是IPerRequestDependencyResolver的WebApi实现,我们使用了GlobalConfiguration。
public class PerRequestWebAPIDependencyResolver : IPerRequestDependencyResolver
{
public T Get <T>() where T : class
{
var config = GlobalConfiguration.Configuration;
return (T)config.DependencyResolver.Current().GetService(typeof(T));
}
}
然后使用动作过滤器来帮助我们添加所需的DependencyResolver:
public class IoCScopeAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
//ioc context set
filterContext.Request.SetCurrentDependencyScope();
}
}
最后在您的控制器或基本控制器中 [AuthorizationFilter] [IoCScope()] public class YourController:ApiController {
}
我希望这有帮助!