我希望在请求的生命周期内动态地将一个实例注入到结构图中(即在注册表/配置之外)。
目前我在HandleBeginRequest
的{{1}}事件中执行此操作:
IHttpModule
但是,如果在应用程序的某些生命中,我会这样做:
container.Configure(x => x.For<IMyClass>()
.LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
.Use(new MyClass()));
我看到ObjectFactory.WhatDoIHave();
的配置实例数量与已有请求(或至少有大量数据)一样。
考虑到这一点,考虑到我的代码,这种方式是有道理的。
有没有更好的方法将实例注入到容器中,只是为了当前请求的生命周期,不会污染整个容器?</ p>
由于
答案 0 :(得分:13)
您的问题是,您在每个请求中注册了一次容器类型,这是在注册时产生的。理想情况下,应在应用程序的生命周期中配置容器一次 - 通常在Web应用程序的Application_Start事件中。
Structuremap允许您指定在创建对象时调用的创建函数,这将允许您配置高级对象创建步骤。
而不是在Begin_Request事件中当前调用Configure,而是在Application_Start期间将以下内容粘贴在容器配置中。
For<IMyClass>().HttpContextScoped().Use(() => new MyClass());
注意Use方法中的lambda。 lambda可以包含创建对象所需的任何逻辑,并且每个生命周期将调用一个逻辑(在HttpContext生命周期的情况下,每个请求)。
答案 1 :(得分:6)
我最终选择了这个
For<IRequestContextStorage>()
.HybridHttpOrThreadLocalScoped()
.Use<RequestContextStorage>();
For<MyClass>()
.Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());
...
public class RequestContextStorage : IRequestContextStorage
{
readonly IDictionary<Type, object> hash;
public RequestContextStorage()
{
this.hash = new Dictionary<Type, object>();
}
public T Get<T>() where T : class
{
if(this.hash.ContainsKey(typeof(T)))
return this.hash[typeof (T)] as T;
return null;
}
public void Set<T>(T instance)
{
this.hash[typeof (T)] = instance;
}
}
...
static void HandleBeginRequest(object sender, EventArgs e) {
ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());
}
答案 2 :(得分:3)
如果您只有一个容器,并且您有多个请求,则会遇到此问题。我建议通过将它们存储在HttpContext.Items中来自己管理每个请求实例。
如果您希望能够通过容器访问它,请创建一个不包含任何状态的网关类,并为您提取HttpContext中的每个请求依赖项。在容器中注册,并将每个请求对象的依赖关系更新为网关。
我不敢相信我之前忽略了这一点,你真正想要的是使用HttpContextLifecycle,它将在HttpContext.Items集合中缓存一个给定的实例,它将在整个请求中可用。在并发请求期间,您仍然会有多个实例处于活动状态,但StructureMap可以根据HttpContext.Current找出要返回的实例。