1

我正在使用 asp.net mvc 和 Structuremap ioc/di 构建小型网上商店。我的篮子类使用会话对象进行持久化,我想使用 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,在官方文档和网站中找不到解决方案/示例;)

4

5 回答 5

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

http://www.lostechies.com/blogs/chad_myers/archive/2008/07/17/structuremap-medium-level-usage-scenarios.aspx

于 2008-11-02T22:31:24.583 回答
1
ForRequestedType<IBasketService>()
    .TheDefault.Is.OfConcreteType<StoreBasketService>()
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);

?? 那样有用吗?

于 2008-12-16T04:40:02.743 回答
0

我刚从 StructureMap 开始,我没有得到你描述的结果。我使用一个简单的类进行了一个简单的测试,将 Structuremap 配置为 cacheby HttpContext,从我所见,CacheBy.HttpContext 意味着在同一个请求中你将获得相同的实例......不在同一个 Session

我的类的构造函数在私有字段中设置日期/时间我有一个按钮,它以一秒的间隔获取 MyClass 的 2 个实例......然后它在标签中显示两个实例的时间。

第一次按下此按钮时,对象 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);
    }

我的课

public class MyClass
{
    private DateTime _timeCreated;
    public MyClass()
    {
        _timeCreated = DateTime.Now;
    }

    public string GetTimeCreated()
    {
        return _timeCreated.ToString("dd/MM/yyyy hh:mm:ss");
    }
}
于 2008-12-08T10:33:10.970 回答
0

您还可以使用 ObjectFactory.Inject 方法之一将 HttpSessionStateBase 注入到 StructureMap 中。然后它将使用注入的 HttpSessionStateBase 调用构造函数。

于 2008-12-08T10:38:06.267 回答
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()));
于 2008-12-08T18:49:22.233 回答