Asp.net mvc StructureMap IOC/DI和对象创建
我正在用asp.net mvc和Structuremap ioc/di构建小型web商店。我的Basket类使用会话对象进行持久化,我希望使用SM通过IBasket接口创建我的Basket对象。我的篮子实现需要构造函数中mvc的HttpSessionStateBase会话状态包装器,该包装器在控制器/操作中可用。如何为SM注册IBasket实现? 这是我的篮子界面:Asp.net mvc StructureMap IOC/DI和对象创建,asp.net-mvc,inversion-of-control,structuremap,Asp.net Mvc,Inversion Of Control,Structuremap,我正在用asp.net mvc和Structuremap ioc/di构建小型web商店。我的Basket类使用会话对象进行持久化,我希望使用SM通过IBasket接口创建我的Basket对象。我的篮子实现需要构造函数中mvc的HttpSessionStateBase会话状态包装器,该包装器在控制器/操作中可用。如何为SM注册IBasket实现? 这是我的篮子界面: public interface IBasketService { BasketContent GetBasket(
public interface IBasketService {
BasketContent GetBasket();
void AddItem(Product productItem);
void RemoveItem(Guid guid);
}
和SM注册:
ForRequestedType(typeof (IBasketService)).TheDefaultIsConcreteType(typeof (StoreBasketService));
但我的StoreBasketService实现具有以下构造函数:
public StoreBasketService(HttpSessionStateBase sessionState)
如何向SM提供HttpSessionStateBase对象,该对象仅在controller中可用?
这是我第一次使用SM IOC/DI,在官方文档和网站中找不到解决方案/示例 如果您必须让StoreBasketService使用会话,我会尝试在HttpSessionState周围定义一个接口和包装器,而不是使用HttpSessionStateBase,以便您也可以使用StructureMap注册它。包装器将从当前上下文获取会话状态。向StructureMap注册包装器,然后让StoreBasketService将接口作为构造函数的参数。然后,结构映射应该知道如何创建接口包装器的实例并将其注入到StoreBasketService类中 使用接口和包装器将允许您在单元测试中模拟包装器,muc的模拟方式与HttpSessionStateBase允许模拟实际会话的方式相同
public interface IHttpSessionStateWrapper
{
HttpSessionState GetSessionState();
}
public class HttpSessionStateWrapper : IHttpSessionStateWrapper
{
public virtual HttpSessionState GetSessionState()
{
return HttpContext.Current.Session;
}
}
ForRquestedType(typeof(IHttpSessionStateWrapper))
.TheDefaultIsConcreteType(typeof(IHttpSessionStateWrapper));
但是,您可以让StructureMap在注册时使用.CacheByInstanceScope.HttpContext在会话中实际存储篮子。实际上,让StoreBasketService实现内部存储而不是在会话中存储可能会更好——这样,从类的角度来看,您就完全失去了对会话状态的依赖,解决方案也会更简单。您的内部存储可以是一个字典,因为这是您通过接口访问它们的方式
另见:
如果您必须让StoreBasketService使用会话,我会尝试在HttpSessionState周围定义一个接口和包装器,而不是使用HttpSessionStateBase,以便您也可以使用StructureMap注册它。包装器将从当前上下文获取会话状态。向StructureMap注册包装器,然后让StoreBasketService将接口作为构造函数的参数。然后,结构映射应该知道如何创建接口包装器的实例并将其注入到StoreBasketService类中 使用接口和包装器将允许您在单元测试中模拟包装器,muc的模拟方式与HttpSessionStateBase允许模拟实际会话的方式相同
public interface IHttpSessionStateWrapper
{
HttpSessionState GetSessionState();
}
public class HttpSessionStateWrapper : IHttpSessionStateWrapper
{
public virtual HttpSessionState GetSessionState()
{
return HttpContext.Current.Session;
}
}
ForRquestedType(typeof(IHttpSessionStateWrapper))
.TheDefaultIsConcreteType(typeof(IHttpSessionStateWrapper));
但是,您可以让StructureMap在注册时使用.CacheByInstanceScope.HttpContext在会话中实际存储篮子。实际上,让StoreBasketService实现内部存储而不是在会话中存储可能会更好——这样,从类的角度来看,您就完全失去了对会话状态的依赖,解决方案也会更简单。您的内部存储可以是一个字典,因为这是您通过接口访问它们的方式
另见:
我只是从StructureMap开始,没有得到您描述的结果。 我使用一个简单的类执行了一个简单的测试,将Structuremap配置为cacheby HttpContext,从我所看到的,cacheby.HttpContext意味着在相同的请求中,您将得到相同的实例。。。不在同一会话中 我的类的构造函数在私有字段中设置日期/时间 我有一个按钮,它以1秒的间隔获取MyClass的2个实例。。。 然后在标签中显示两个实例的时间 第一次按下此按钮时,对象A和B是相同的实例,因为它们的创建时间与预期完全相同 如果在会话中缓存实例,第二次单击该按钮,您可能会认为创建时间没有更改。。。然而,在我的测试中,我得到了一个新的创建时间 结构映射配置:
我只是从StructureMap开始,没有得到您描述的结果。 我使用一个简单的类执行了一个简单的测试,将Structuremap配置为cacheby HttpContext,从我所看到的,cacheby.HttpContext意味着在相同的请求中,您将得到相同的实例。。。不在同一会话中 我的类的构造函数在私有字段中设置日期/时间 我有一个按钮,它以1秒的间隔获取MyClass的2个实例。。。 然后在标签中显示两个实例的时间 第一次按下此按钮时,对象A和B是相同的实例,因为它们的创建时间与预期完全相同 如果在会话中缓存实例,第二次单击该按钮,您可能会认为创建时间没有更改。。。豪 在我的测试中,我得到了一个新的创建时间 结构映射配置:
您还可以使用ObjectFactory.Inject方法之一将HttpSessionStateBase注入StructureMap。然后,它将使用注入的HttpSessionStateBase调用构造函数。您还可以使用ObjectFactory.Inject方法之一将HttpSessionStateBase注入StructureMap。然后,它将使用注入的HttpSessionStateBase调用构造函数。我刚刚第一次尝试创建自定义范围。。。用它构建一个小型web应用程序,就我所见,它似乎可以工作。这将在当前用户会话中缓存对象,并且只要您仍在同一会话中,就会返回相同的对象:
public class HttpSessionBuilder : CacheInterceptor
{
private readonly string _prefix = Guid.NewGuid().ToString();
protected override CacheInterceptor clone()
{
return this;
}
private string getKey(string instanceKey, Type pluginType)
{
return string.Format("{0}:{1}:{2}", pluginType.AssemblyQualifiedName, instanceKey, this._prefix);
}
public static bool HasContext()
{
return (HttpContext.Current.Session != null);
}
protected override bool isCached(string instanceKey, Type pluginType)
{
return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)] != null;
}
protected override object retrieveFromCache(string instanceKey, Type pluginType)
{
return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)];
}
protected override void storeInCache(string instanceKey, Type pluginType, object instance)
{
HttpContext.Current.Session.Add(this.getKey(instanceKey, pluginType), instance);
}
}
您必须在global.asax应用程序_start中配置ObjectFactory,如下所示
ObjectFactory.Initialize(x=>
x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
我刚刚第一次尝试创建自定义范围。。。用它构建一个小型web应用程序,就我所见,它似乎可以工作。这将在当前用户会话中缓存对象,并且只要您仍在同一会话中,就会返回相同的对象:
public class HttpSessionBuilder : CacheInterceptor
{
private readonly string _prefix = Guid.NewGuid().ToString();
protected override CacheInterceptor clone()
{
return this;
}
private string getKey(string instanceKey, Type pluginType)
{
return string.Format("{0}:{1}:{2}", pluginType.AssemblyQualifiedName, instanceKey, this._prefix);
}
public static bool HasContext()
{
return (HttpContext.Current.Session != null);
}
protected override bool isCached(string instanceKey, Type pluginType)
{
return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)] != null;
}
protected override object retrieveFromCache(string instanceKey, Type pluginType)
{
return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)];
}
protected override void storeInCache(string instanceKey, Type pluginType, object instance)
{
HttpContext.Current.Session.Add(this.getKey(instanceKey, pluginType), instance);
}
}
您必须在global.asax应用程序_start中配置ObjectFactory,如下所示
ObjectFactory.Initialize(x=>
x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
???这样行吗
???那有用吗?我今天就试试,thanx。但对于使用SM缓存Basket类,IS.Httpcontext将对象存储在Httpcontext.items字典中,该字典仅在一个页面请求中可用,但我希望它贯穿整个用户会话。今天我将尝试一下,thanx。但对于使用SM缓存Basket类,IS.Httpcontext将对象存储在Httpcontext.items字典中,该字典仅在一个页面请求中可用,但我希望它贯穿整个用户会话。
ObjectFactory.Initialize(x=>
x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
ForRequestedType<IBasketService>()
.TheDefault.Is.OfConcreteType<StoreBasketService>()
.WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);