Using Unity with ASP.NET MVC 3 for an object stored in Session
I've got an MVC controller that stores an object in Session. Different controller actions retrieve the object from Session, do stuff with it, and save it back.
I'd like to use Unity so that the controller just deals with an interface, but I'm not sure how to achieve this (I'm fairly new to the whole dependency injection thing). Here's some sample code:
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();
}
}
So basically I want to开发者_运维问答 use IState
instead of State
. But where/how does Unity inject the concrete implementation? It seems like it can't happen in the constructor, because I only need to instantiate a new object in the Index()
action. Is there maybe some magic way I can add a parameter to Index()
that Unity can use?
If you want to use Unity you must change your implementation little bit. You must define your controller as:
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();
}
}
Now you need two additional step. You must use PerSessionLifetime manager for your IState
resolving and you must configure Unity to resolve controllers and their dependencies - there is some build in support for resolving in ASP.NET MVC 3.
Unity doesn't provide PerSessionLifetime manager so you must build your own.
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);
}
}
You can use this lifetime when configuring controller or you can configure extension in unity configuration and define your 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>
You might want to do this with an ActionFilter. The ActionFilter could grab the object from session state (instantiating it if needed), and add it to your ActionParameters collection.
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"];
}
}
Then, your Index action looks like this:
[HttpGet]
[IncludeState]
public ActionResult Index(State state)
{
// do stuff with state
return View();
}
The only thing I'm unsure about is where your key comes from.
I realize that this doesn't use Unity, but maybe you don't need it.
精彩评论