tags:

views:

321

answers:

2

I need some help with the follow:

I have just read on this tutorial: http://www.asp.net/LEARN/mvc/tutorial-13-cs.aspx

and followed the example given for the "good solution". However, I encountered a problem after i made some modifications to the abstract class ApplicationController.

The original constructor was:

public ApplicationController()
{                
    ViewData["categories"] = from c in DataContext.MovieCategories
                             select c;           
}

I've modified it to become to use a stored procedure instead:

public ApplicationController()
{                
    ViewData["categories"] =  DataContext.spMovieCategories("some movie category");
}

Is there anyway I can pass in "some movie category" as a parameter? I've tried using TempData and Session variables but it keeps throwing me errors.

Thanks guys!

A: 

You can use a parameter in the constructor to pass it in:

public ApplicationController(string movieCategory)
{
    ViewData["categories"] = DataContext.spMovieCategories(movieCategory);
}

Obviously, you'd need to be able to supply this from the derived controllers, which may be an issue unless the category is specific to each derived controller which seems unlikely:

public DerivedController() : base("Derived Movie Category")
{
    // ...
}

What is probably best is to move the categories retrieval out of the constructor, and move it into a separate method in ApplicationController. The simplest way of getting this called is then to insert a call to it in each Action once you have the category parameter (I'm assuming it's one of the parameters to the Action call?). This is a bit of a pain though.

The intended way to solve this problem is ActionFilters, if you create a new ActionFilter like this:

public class CategoryAttribute : ActionFilterAttribute, IActionFilter
{
    #region IActionFilter Members

    void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
    {
        string category = (string)filterContext.RouteData.Values["category"];
        ((ApplicationController)filterContext.Controller).PopulateCategory(category);
    }

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
    }

    #endregion
}

Any action with the Category attribute applied will execute this code. (I've assumed that you've moved the code in ApplicationController into a method called PopulateCategory. You can also apply it at the Controller level, which then will cause this ActionFilter to be called for every action in the controller.

Since you want it to be called for every action on every controller, you can apply it to your ApplicationController so that every derived controller will inherit it:

[Category]
public class ApplicationController : Controller
{
    // ...
}

[Edit - Slightly better solution]

However, an even further step to simplify is to not use an attribute, but instead to override the OnActionExecuted method of Controller (that I just noticed after I wrote this answer).

That means you can get rid of the CategoryAttribute class and the Category attribute on the ApplicationController class and just add this to the ApplicationController class:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    string category = (string)filterContext.RouteData.Values["category"];
    this.PopulateCategory(category);
    base.OnActionExecuted(filterContext);
}
Giraffe
A: 

Hi there,

I have done this by creating my own ViewDataPage class that inherits the System.Web.Mvc.ViewDataPage.

namespace myWebsite.Helpers
{
public class ViewMasterPage : System.Web.Mvc.ViewMasterPage
{
    public bcData Data = new bcData();

}
}

Change the web.config to include your namespace:

  <namespaces>
    <add namespace="betClubUk.Helpers" />
  </namespaces>

Then implement the data in the view.

<%@ Master Language="C#" Inherits="betClubUk.Helpers.ViewMasterPage" %>

<%=Data.getVariableContent().statOfDay.text %>
Oliver