Wavel
Wavel

Reputation: 966

MVC 4 How to process a url parameter on every page, base controller?

Looking for some guidance in designing my new MVC 4 app.

I would like to have a url parameter s=2011 on every page of the app to let me know what year of data I'm working with. Obviously, the user will have a way to change that parameter as needed.

I will need that parameter in every controller and wondering the best way to do this. I was thinking of creating a base controller that reads Request.QueryString and puts the year into a public property. However, considering all the extensability points in MVC, I'm wondering if there's a better way to do this?

Upvotes: 2

Views: 880

Answers (1)

Ivan Zlatev
Ivan Zlatev

Reputation: 13196

This very much depends on the design of your app, but just to give you two alternatives

IActionFilter

If you are doing data context per request you can use a global IActionFilter to hook pre-action execution globally and apply a query filter to your data context behind the scenes.

Major down-side of this is that to test the controller you will need to have the full MVC pipeline setup so that the actionfilter gets applied properly.

Dependency Injection

Instead of using sub-classing (base controller as you say) you can use dependency injection . Keeping things more loose will allow you to pull the filter from query string, cookie, user setting in the database or whatever else - without your controller knowing where it comes from.

Here is some pseudo code how I would do it if I was using something like Entity Framework or Nhibernate (also I am sure applicable with other technologies as well)

public Car
{
    public string Year { get; set; }
}

public class CarsDataContext : DbContext
{
    private IQuerable<Cars> _cars = null;
    private Func<Car, bool> _carsFilter = null;

    public IQuerable<Car> Cars {
        get {
            if (_carsFitler != null)
                return _cars.Where(_carsFitler);

            return _cars;
        } 
        set { _cars = value; }
    }

    public void ApplyCarsFilter(Func<Car, bool> predicate)
    {
        _carsFilter = predicate;
    }
}

Assuming you have dependency injection setup already (NInject or whichever other framework) in you can configure how the context to be intialized

Bind<CarsDataContext>().ToMethod(() => {
    string yearFilter = GetYearFilter(); // can be coming from anywhere

    CarsDataContext dataContext = new CarsDataContext();
    dataContext.Applyfilter(car => car.Year == yearFilter);
    return dataContext;
}).InRequestScope();

Then my controller knows nothing about the data filtering and I can easily test it:

class MyController : Controller
{
    public MyController(CarsDataContext dataContext)
    {
    }
    ...
}

However I would only do this is filtering the dataset was across many controllers and important part of my software. Otherwise it's pure over-engineering.

Upvotes: 1

Related Questions