【问题标题】:Using Unity with ASP.NET MVC 3 for an object stored in Session将 Unity 与 ASP.NET MVC 3 一起用于存储在 Session 中的对象
【发布时间】:2011-05-13 15:10:05
【问题描述】:

我有一个在 Session 中存储对象的 MVC 控制器。不同的控制器操作从 Session 中检索对象,对其进行处理,然后将其保存回来。

我想使用 Unity,以便控制器只处理一个接口,但我不确定如何实现这一点(我对整个依赖注入这件事还很陌生)。下面是一些示例代码:

public class MyController : Controller
{
   [HttpGet]
   public ActionResult Index()
   {
      var state = new State();
      // do stuff with state
      Session[Key] = state;
      return View();
   }

   [HttpPost]
   public ActionResult Change()
   {
      var state = Session[Key] as State;
      // do stuff with state
      Session[Key] = state;
      return View();
   }
}

所以基本上我想使用IState 而不是State。但是 Unity 在哪里/如何注入具体实现?在构造函数中似乎不可能发生,因为我只需要在Index() 操作中实例化一个新对象。有没有什么神奇的方法可以向 Index() 添加 Unity 可以使用的参数?

【问题讨论】:

    标签: asp.net-mvc-3 dependency-injection unity-container


    【解决方案1】:

    如果你想使用 Unity,你必须稍微改变你的实现。您必须将控制器定义为:

    public class MyController : Controller
    {
       private IState _state;
    
       public MyController(IState state)
       {
           _state = state;
       }
    
       [HttpGet]
       public ActionResult Index()
       {
          // Fill the state but you cannot change instance!
          _state.A = ...;
          _state.B = ...;
    
          return View();
       }
    
       [HttpPost]
       public ActionResult Change()
       {
          // Fill the state but you cannot change instance!
          _state.A = ...;
          _state.B = ...;
    
          return View();
       }
    }
    

    现在您需要两个额外的步骤。您必须使用 PerSessionLifetime 管理器进行 IState 解析,并且您必须配置 Unity 以解析控制器及其依赖项 - 有一些 build in support for resolving in ASP.NET MVC 3

    Unity 不提供 PerSessionLifetime 管理器,因此您必须自己构建。

    public class PerSessionLifetimeManager : LifetimeManager
    {
        private readonly Guid _key = Guid.NewGuid();
    
        public override object GetValue()
        {
            return HttpContext.Current.Session[_key];
        }
    
        public override void SetValue(object newValue)
        {
            HttpContext.Current.Session[_key] = newValue;
        }
    
        public override void RemoveValue()
        {
            HttpContext.Current.Session.Remove(_key);
        }
    }
    

    您可以在配置控制器时使用此生命周期,也可以在统一配置中配置扩展并定义您的IState

    <configuration>
      <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
      </configSections>
      <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
        <alias alias="perSession" type="NamespaceName.PerSessionLifetimeManager, AssemblyName"/>
        <alias alias="IState" type="NamespaceName.IState, AssemblyName" />
        <alias alias="State" type="NamespaceName.State, AssemblyName" />
        <container name="Web">
          <register type="IState" mapTo="State" >
            <lifetime type="perSession" />
          </register>
        </container>
      </unity>
    </configuration>
    

    【讨论】:

    • 像魅力一样工作。谢谢!我正在 Global.asax 中进行 Unity 设置(在代码而不是配置中),所以我做了container.RegisterType&lt;IState, State&gt;(new PerSessionLifetimeManager());
    • 嗯,实际上,我想我可能错过了什么。如果我在控制器中更改 State 类,如何将其保存回 Session
    • 您只能更改属性。您无法更改实例。
    【解决方案2】:

    您可能希望使用 ActionFilter 来执行此操作。 ActionFilter 可以从会话状态中获取对象(如果需要,将其实例化),并将其添加到您的 ActionParameters 集合中。

    public class IncludeStateAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(...)
        {
            var currentState = filterContext.HttpContext.Session[Key] as State;
            if (currentState == null)
            {
                currentState = new State();
            }
    
            filterContext.ActionParameters["state"] = currentState
        }
    
        public override void OnActionExecuted(...)
        {
            filterContext.HttpContext.Session[Key] = filterContext.ActionParameters["state"];
        }
    }
    

    然后,您的 Index 操作如下所示:

    [HttpGet]
    [IncludeState]
    public ActionResult Index(State state)
    {
        // do stuff with state
        return View();
    }
    

    我唯一不确定的是您的密钥来自哪里。

    我知道这不使用 Unity,但也许你不需要它。

    【讨论】:

    • 这似乎是个好主意,但如果我想单独测试这个过滤器,我想我会遇到同样的问题。 Session 的键只是一个常数。我想使用 Unity 将我的控制器与我的 State 类分离,这样我就可以在不接触 State 代码的情况下测试控制器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多