views:

51

answers:

2

Is it possible for a Controller Base class to access a parameter from an action link and if so how do I access that parameter within my Base Controller?

Action Link:

<%=Url.Action("Area_1419", "Home", new { SectionId = 1})%>

Base Controller Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Website.Models;

namespace Website.Controllers
{
    public abstract class CategoriesController : Controller
    {
        public CategoriesDataContext _dataContext = new CategoriesDataContext();

        public CategoriesDataContext DataContext
        {
            get { return _dataContext; }
        }

        public void SectionID()
        {
            int SectionID = Convert.ToInt32(Request.QueryString["SectionID"]);
            ViewData["SectionID"] = SectionID;
        }

        public CategoriesController2()
        {
            //ViewData["Categories"] = from m in _dataContext.Categories where m.Area_ID == SectionID select m;
            //ViewData["Categories"] = from c in DataContext.Categories select c;
        }
    }
}

HomeContoller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Website.Models;
using Website.ActionFilters;

namespace Website.Controllers
{
    [HandleError]
    public class HomeController : CategoriesController
   {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About(int? SectionID)
        {
            //ViewData["Message"] = SectionID;
            return View();
        }

        public ActionResult Area_1419(int SectionID)
        {
            return View();
        }


        public ActionResult Admin()
        {
            return View();
        }
    }
}
+1  A: 

The base class cannot access arguments passed to a controller action, but it can get data out of RouteData. So if you want SectionId to be part of your route, rather than a querystring argument, you could do:

// Global.asax
routes.MapRoute(
    "WithSection",
    "{sectionId}/{controller}/{action}/{id}",
    new { section = String.Emtpy, action = "index", id = String.Empty }
);

// base controller class
public void SectionID()
{
  int SectionID = Convert.ToInt32(RouteData["SectionID"]);
  ViewData["SectionID"] = SectionID;
}

If you're passing SectionId as a querystring parameter then the code you posted should work... does it not?

Seth Petry-Johnson
Thanks for the replies. I belive I'm passing SectionID as a querystring. When I place the code Request.QueryString in my Home Controller it works fine, but not in my Base Controller.
Jemes
That sounds very odd. Perhaps you should post the relevant portions of HomeController and BaseController. Also, if you hook up a debugger and step through the code, do you get different QueryString values?
Seth Petry-Johnson
I've updated my question.
Jemes
A: 

Typically you would have a property in BaseController which you set in a Filter.

Something like

    public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
              ((BaseController)filterContext.Controller).SectionID = "Something";
     }

But beware that this property should not be used in other filters, because the order of execution is not predictable by default.

Malcolm Frexner
Why do you prefer this over a property of the base controller that indexes into ViewData? I've done it both ways but I like the property more... it seems a little more explicit (b/c you can easily tell from the property declaration where the value is coming from) plus it allows you to use the value in other action filters. Normally I use a lazy-loaded property that wraps ViewData unless a value is explicitly set, which allows me to easily hard code a value during testing.
Seth Petry-Johnson
To be honest I never had the idea you showed. My base controller has very little code. Your solution definitily makes sense.
Malcolm Frexner