2011-05-13 97 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

相關問題