我正在使用asp.net mvc和Structuremap ioc / di建立小型网上商店。我的Basket类使用会话对象进行持久化,我想使用SM通过IBasket接口创建我的篮子对象。我的篮子实现需要构造函数中的HttpSessionStateBase(来自mvc的会话状态包装器),它在Controller / Action中可用。如何为SM注册我的IBasket实现?
这是我的购物篮界面:
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对象,仅在控制器中可用? 这是我第一次使用SM IOC / DI,在官方文档和网站上找不到解决方案/示例;)
答案 0 :(得分:4)
如果你必须让你的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));
public class StoreBasketService
{
HttpSessionState session;
public StoreBasketService( IHttpSessionstateWrapper wrapper )
{
session = wrapper.GetSessionState();
}
// basket implementation ...
}
但是,您可以让StructureMap在注册时使用.CacheBy(InstanceScope.HttpContext)
在会话中实际存储您的购物篮。让StoreBasketService实现内部存储而不是在会话中存储东西实际上可能更好 - 然后你完全失去了对会话状态的依赖(从你的类的角度来看),你的解决方案可能更简单。您的内部存储空间可能是Dictionary<Guid,Product>
,因为这是您通过界面访问它们的方式。
另见:
http://www.lostechies.com/blogs/chad_myers/archive/2008/07/15/structuremap-basic-scenario-usage.aspx
答案 1 :(得分:1)
ForRequestedType<IBasketService>()
.TheDefault.Is.OfConcreteType<StoreBasketService>()
.WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);
??这有用吗?
答案 2 :(得分:0)
我刚开始使用StructureMap,但我没有得到您描述的结果。 我使用一个简单的类执行了一个简单的测试,将Structuremap配置为cacheby HttpContext,从我所看到的,CacheBy.HttpContext意味着在同一个请求中你将获得相同的实例...不在同一个Session中
我班级的构造函数,在私有字段中设置日期/时间 我有一个按钮,获得2个MyClass实例,间隔一秒...... 然后它会在标签中显示两个实例的时间。
第一次按下此按钮,对象A和B是同一个实例,因为它们的创建时间与预期完全相同。
再次单击该按钮,如果在会话中缓存实例,您可能希望创建时间没有更改...但是,在我的测试中,我获得了新的创建时间......
结构图配置:
ObjectFactory.Initialize(x=>x.ForRequestedType<MyClass>(). CacheBy(InstanceScope.HttpContext));
按钮点击了测试页的事件
protected void btnTest_Click(object sender, EventArgs e)
{
MyClass c = ObjectFactory.GetInstance<MyClass>();
System.Threading.Thread.Sleep(1000);
MyClass b = ObjectFactory.GetInstance<MyClass>();
lblResult.Text = String.Format("cache by httpcontext First:{0} Second:{1} session id {2} ", c.GetTimeCreated(), b.GetTimeCreated(),Session.SessionID);
}
<强> MyClass的强>
public class MyClass
{
private DateTime _timeCreated;
public MyClass()
{
_timeCreated = DateTime.Now;
}
public string GetTimeCreated()
{
return _timeCreated.ToString("dd/MM/yyyy hh:mm:ss");
}
}
答案 3 :(得分:0)
您还可以使用ObjectFactory.Inject方法之一将HttpSessionStateBase注入StructureMap。然后它将使用注入的HttpSessionStateBase调用构造函数。
答案 4 :(得分:0)
我刚刚尝试创建自定义范围...使用它构建一个小型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 Application_start
中按如下方式配置ObjectFactory ObjectFactory.Initialize(x=>
x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));