views:

377

answers:

3

Hi folks,

I am using the UserData Property of the FormsAuthenticationTicket to store some userspecific information. I have a HelperClass which deserializes this UserData into a custom Object for strongly-typed access. I have my controller setup as follows

public class SomeController : Controller
{
    private CookieData _cookieData;

    public SomeController()
    {
        _service = new ForderungsStellerService(new ModelStateWrapper(this.ModelState));
        HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
        _cookieData= GetSessionData.FromCookie(ticket);
    }
}

The problem seems to be, that Request is null at controller construction time. When accessing Request.Cookies from an ActionMethod, this snippet is working.

I would like to have the _cookieData object be filled within the constructor for DRY reasons.

Does anyone has a hint on that problem?

best regards...

+2  A: 

I would create a ModelBinder that understands CookieData and how to get it out of the Request object. I fear the unit-test creation code necessary to make the constructor happy. If you take it as a parameter to the controller with a Model Binder you can avoid that test overhead.

public class SomeController : Controller
{
  // only need to pass in the data object for unit testing.
  // ModelBinder takes care of DRY
  public ActionResult Index(CookieData cookieData)
  {
  }
}

The answer to why it doesn't work in the constructor is that the Controller hasn't been initialized with the ControllerContext at that point.

public HttpContextBase HttpContext {
  get {
    return ControllerContext == null 
      ? null 
      : ControllerContext.HttpContext;
  }
}

If you really want to do it in the constructor (don't) then use HttpContext.Request instead of the wrapper. But by doing so you will have made your code untestable and your alignment will drop by 3 points.

Talljoe
Using a ModelBinder is a smart idea. Thanks for it. Solved my problem...
Gordon
A: 

Its good to be DRY but in case of ASP.NET MVC it most often means using a custom filter attribute or like talljoe showed a Model Binder.

    public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         HttpCookie cookie = filterContext.HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
        filterContext.ActionParameters["CookieData"] = GetSessionData.FromCookie(ticket);


         base.OnActionExecuting(filterContext);
     }
Malcolm Frexner
A: 

Override Controller.Initialize():

protected override void Initialize(RequestContext requestContext) {
  base.Initialize(requestContext);
  // do further initialization here
}

Properties like Request, etc. will be available to you after the call to base.Initialize().

Levi
Also a right solution. Would work, but makes unittests harder as it should be.
Gordon