Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC - Set ViewData for masterpage in base controller

I'm using a masterpage in my ASP.NET MVC project. This masterpage expects some ViewData to be present, which displays this on every page.

If I don't set this ViewData key in my controllers, I get an error that it can't find it. However, I don't want to set the ViewData in every controller (I don't want to say ViewData["foo"] = GetFoo(); in every controller).

So, I was thinking of setting this in a base controller, and have every controller inherit from this base controller. In the base controller default constructur, I set the ViewData. I found a similar approach here: http://www.asp.net/learn/MVC/tutorial-13-cs.aspx. So far so good, this works... but the problem is that this data comes from a database somewhere.

Now when I want to Unit Test my controllers, the ones that inherit from the base controller call its default constructor. In the default constructor, I initialize my repository class to get this data from the database. Result: my unit tests fail, since it can't access the data (and I certainly don't want them to access this data).

I also don't want to pass the correct Repository (or DataContext, whatever you name it) class to every controller which in turn pass it to the default controller, which I could then mock with my unit tests. The controllers in turn rely on other repository classes, and I would end up passing multiple parameters to the constructor. Too much work for my feeling, or am I wrong? Is there another solution?

I've tried using StructureMap but in the end I didn't feel like that is going to fix my problem, since every controller will still have to call the base constructor which will initialize the repository class, so I can't mock it.

This is a similar question but I find no satisfactory answer was given. Can I solve this in a neat way, maybe using StructureMap as a solution? Or should I jsut suck it and pass a Repository to every controller and pass it again to the base controller? Again, It feels like so much work for something so simple. Thanks!

like image 542
Razzie Avatar asked Jun 10 '09 15:06

Razzie


Video Answer


1 Answers

I see two options:

First:

Set the ViewData for MasterPage in YourBaseController.OnActionExecuting() or YourBaseController.OnActionExecuted():

public class YourBaseController : Controller {     protected override void OnActionExecuting(ActionExecutingContext filterContext)     {         // Optional: Work only for GET request         if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")             return;          // Optional: Do not work with AjaxRequests         if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())             return;          ...          filterContext.Controller.ViewData["foo"] = ...     } } 

Second:

Or create custom filter:

public class DataForMasterPageAttribute : ActionFilterAttribute {     public override void OnActionExecuting(ActionExecutingContext filterContext)     {         // Optional: Work only for GET request         if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")             return;          // Optional: Do not work with AjaxRequests         if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())             return;          ...          filterContext.Controller.ViewData["foo"] = ...     } } 

and then apply to your controllers:

[DataForMasterPage] public class YourController : YourBaseController {     ... } 

I think the second solution is exactly for your case.

like image 74
eu-ge-ne Avatar answered Oct 06 '22 08:10

eu-ge-ne