2011-05-13 141 views
2

我有一个在Session中存储对象的MVC控制器。不同的控制器操作从Session中检索对象,对其进行处理并保存回去。在ASP.NET MVC 3中使用Unity存储在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()操作中实例化一个新对象。有没有什么神奇的方法可以给Unity添加参数Index()

回答

2

如果你想使用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> 
+0

工程就像一个魅力。谢谢!我正在做Global.asax中的Unity设置(代码而不是配置),所以我做了'container.RegisterType (新的PerSessionLifetimeManager());' – 2011-05-17 09:19:27

+0

嗯,实际上,我想我可能有错过了什么。如果我在我的控制器中改变'State'类,它是如何被保存回'Session'的? – 2011-05-17 10:14:36

+0

您只能更改属性。你不能改变实例。 – 2011-05-17 10:16:50

0

你可能想用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"]; 
    } 
} 

然后,你的索引操作是这样的:

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

我不能确定的唯一的事情就是你的关键来源。

我意识到这不使用Unity,但也许你不需要它。

+0

这似乎是一个不错的主意,但我想我会正好碰上如果我想单独测试此过滤器,则会出现同样的问题。会议的关键只是一个常数。我想使用Unity来将我的控制器从我的状态类中解除耦合,所以我可以在不触摸状态代码的情况下测试控制器。 – 2011-05-17 09:17:54

相关问题