ASP.Net MVC Routing and the PreRequestHandler - asp.net-mvc

I'm trying to instantiate a service and authenticate the current user within the Application_PreRequestHandlerExecute() method and then dispose of this service in the* Application_PostRequestHandlerExecute() method of the global.asax.cs class. One of the items I need for this process is the orgname which is appended at the beginning of my url route. I have mapped a route that looks like this "{orgName}/{controller}/{action}/{id}"
So my question is, within an ASP.Net MVC application is it possible to access any of the routing information (or somehow access the "orgname" in my instance) within the Application_PreRequestHandlerExecute() event? If this is not possible is there some other way to hook into an MvcHandler and do something similar (maybe I should build a custom filter?)

You need the "RequestContext" to find all the route values. I don't know any other way to get them than inside the controller.
You sould implement a "ActionFilterAttribute", then decorate your controllers with it.
the ActionFilter has the methods
// Called after the action method executes.
public virtual void OnActionExecuted(ActionExecutedContext filterContext);
// Called before the action method executes.
public virtual void OnActionExecuting(ActionExecutingContext filterContext);
that you can do all sorts of fun stuff in.

Related

How to handle site-wide querystring parameters in MVC?

I need to be able to process a querystring parameter throughout the site (like ?promo=38 for example). I was trying the procedure specified here Passing a {sitename} parameter to MVC controller actions but it wasn't working. My guess it's because according to http://blog.stevensanderson.com/2007/11/20/aspnet-mvc-pipeline-lifecycle/ querystring processing happens after the controller is instantiated.
So what would be a simple way to accomplish what I want? namely, being able to do something like setting a base controller property, or setting a session variable, from a querystring parameter anywhere in my site, without having to manually specify something in all the controller actions?
Override OnActionExecuting() your base controller or in an Action Filter as suggested by #jrummell. An Action Filter might be the way to go, but you would still need to decorate all of your controllers or create a base controller and decorate that with it.
public class PromoActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewBag.Promo = filterContext.HttpContext.Request.QueryString("Promo");
base.OnActionExecuting(filterContext);
}
}
[PromoActionFilter]
public class BaseController : Controller
{
... Some Actions ...
}

Dependency Injection into an MVC action method

I'm wondering if this is possible. I have a typical MVC action method with a signature that looks like this:
public ActionResult View(MyModel model)
{
IAnObject myObject = new AnObject();
//several lines of code follow.....
return View(model);
}
I'd like to get rid of that new keyword and inject an instance of IAnObject into the action method. But I'm not sure if MVC allows for this, injecting a class along side a model in an action method? Has anyone run across this, and are there ways of tackling it? (Our IoC container is Windsor, in case that makes a difference.)
If you are expecting to inject this reference into the action method as a parameter, you can look to the ControllerActionInvoker, which has an InvokeActionMethod method, which I believe is called from InvokeAction. This method has a list of parameters passed into it, and a description of the action (ActionDescriptor class). This action descriptor has a GetParameters method that will give you more detailed information about the parameter, such as type information that you would need for the dependency injector. I've not done this, so I don't know quite how it works out, but it seems possible.
I also don't know how that might affect how MVC selects an action method to post to, so factor that in.
You may want to do your injection in OnActionExecuting which is called before any action on the controller is executed. This will give you context such as the Request but will allow you to set member variables - thus 'simulating' constructor injection. And of course you only have to do it once for the whole controller.
[NonAction]
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_myService = .........; // get from IoC container
base.OnActionExecuting(filterContext);
}
Well, I agree with the guys on the comments, but if you want to take an instance in the method scope, try to get it from your container of IoC, something like this:
public ActionResult View(MyModel model)
{
// take from the container of IoC
IAnObject myObject = _continerIoC.Resolve<IAnObject >();
//several lines of code follow.....
return View(model);
}
Avoid using the new to create your instance and your concrete type in the container and decouple your controller from dependecies/references.
I really consider using constructor/property Injection. There is a method injection too.

Multilingual URLs with ASP.NET MVC

I’m working out the concepts for a new project where I need to support for multilingual URL’s. Ideally all URL’s need to be in the native language of the user. So we don’t want to use domain.com/en/contact and domain.com/es/contact but we like domain.com/contact and domain.com/contactar (contactar is Spanish for contact). Internally both should be routed to the same ContactController class.
This could be handled by adding multiple static routes to Global.asax.cs for each language but we’d like to make this very dynamic and would like the user of the system to be able to change the translation of the URL’s through the content management system. So we need some kind of dynamic mapping from URL’s to controllers and actions.
By looking at the source code of MVC3 I figured out that the ProcessRequestInit method of MvcHandler is responsible for determining which controller to create. It simply looks in the RouteData to get the name of the controller. One way to override the default MVC routing would be to create a simple default route that uses a custom RouteHandler. This RouteHandler forces MVC to use my own custom subclassed version of MvcHandler that overrides the ProcessRequestInit method. This overridden method insert my own dynamically found controller and action into the RouteData before calling back to the original ProcessRequestInit.
I’ve tried this:
Global.asax.cs
routes.Add(
new Route("{*url}", new MultilingualRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Default", action = "Default" })
}
);
MultilingualRouteHandler.cs
public class MultilingualRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MultilingualMVCHandler(requestContext);
}
}
MultilingualMvcHandler.cs
public class MultilingualMVCHandler : MvcHandler
{
public MultilingualMVCHandler(RequestContext context) : base(context)
{
}
protected override void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
if (RequestContext.RouteData.Values.ContainsKey("controller"))
{
RequestContext.RouteData.Values.Remove("controller");
}
if (RequestContext.RouteData.Values.ContainsKey("action"))
{
RequestContext.RouteData.Values.Remove("action");
}
RequestContext.RouteData.Values.Add("controller", "Product");
RequestContext.RouteData.Values.Add("action", "Index");
base.ProcessRequestInit(httpContext, out controller, out factory);
}
}
In this handler I hardcoded the controller and action for testing purposes to some fixed values but it’s not difficult to make this dynamic. It works but the only problem is that I had to modify the source code of ASP.NET MVC3 to get it working. The problem is that the ProcessRequestInit method of MvcHandler is private and thus cannot be overridden. I’ve modified the source code and changed it to protected virtual which allows me to override it.
This is all great but possibly not the best solution. It’s cumbersome that I would always need to distribute my own version of System.Web.Mvc.dll. It would be much better that it would work with the RTM version.
Am I missing any other possibilities of hooking into ASP.NET MVC that would allow me to dynamically determine the controller and action to launch, depending on the URL? One other way I thought of is to build the RouteCollection dynamically on *Application_Start* but I think that will make it more difficult to change it on the fly.
I would appreciate any tips of hooks that I’ve not yet found.
This is fairly old now, nut just in case anyone else is looking for something similar...
Unless I'm completely misunderstanding what you want to do, it's pretty simple really.
Step 1: Add a new route to global.ascx.cs containing a reference to your personal routing engine
routes.Add(new MyProject.Routing.ContentRoutingEngine());
Make sure that it is in the right place in the list of routes so that other routing engines can catch stuff before it if required, or continue the route search if your engine doesn't handle a particular route. I put it after the ignores, but before the MVC default routes.
Step 2: Create the Content Routing Engine, making sure that it inherites from System.Web.Routing.RouteBase abstract class, and overrides the GetRouteData and GetVirtualPath methods as required e.g.
public class ContentRoutingEngine : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var routeHandler = new MvcRouteHandler();
var currentRoute = new Route("{controller}/{action}", routeHandler);
var routeData = new RouteData(currentRoute, routeHandler);
// set your values dynamically here
routeData.Values["controller"] = "Home" ;
// or
routeData.Values.Add("action", "Index");
// return the route, or null to have it passed to the next routing engine in the list
return routeData;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
//implement this to return url's for routes, or null to just pass it on
return null;
}
}
and that should do it. You can change routes as dynamically as you wish within your engine, and no changes to MVC source required. Let the standard MVC RouteHandler actually invoke the controller.
Postscript: Obviously the code above is not production standard - it's written to make it as obvious as possible what's going on.
If you are allowing modification of urls through your CMS, then you will have to keep all old versions of the urls so that you can 301 redirect to the new ones.
The best bet for this will be to put the url tokens eg "contactar" in the db along with its corresponding controller.
query that, and create your routes out of that.
create a route that will handle the 301s
I think that most elegant solution would be using some action filter combined with custom ActionInvoker. That way, you could invoke an action that has specific filters applied. Something like ActionName attribute, only capable to accept multiple values (names).
Edit: Take a look at ActionMethodSelectorAttribute, meybe you don't need a custom ActionInvoker after all.

Check conditions on each page request

I have multi-tenant ASP.NET MVC application which utilizes subdomains to determine the current tenant. Whether or not the domain is valid is determined via database table lookup.
Where would be the best place to have a function that checks if the domain is in the database?If the subdomain is not in the database, it should redirect to the Index action in the Error controller.
Placing the check in the Application_BeginRequest method in the Global.asax file doesn't work because a never ending redirect results.
Where would be the best place to have a function that checks if the domain is in the database?If the subdomain is not in the database, it should redirect to the Index action in the Error controller.
Placing the check in the Application_BeginRequest method in the Global.asax file doesn't work because a never ending redirect results.
That's the right place, you just need to check the request Url is not already /Error.
You might already be doing so, but I'd like to add that it seems pretty static information that you should cache instead of hitting the database for each request.
u can subclass actionFilter attribute and override onactionExecuting method. in this method u can make any database checks and redirect the user appropriately
public class CustomActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if(DatabaseLookup)
{
return;
}
filterContext.Result = new RedirectResult("http://servername/Error");
}
}
now u can decorate ur action methods with this custom actionfilter attribute
[CustomActionFilter]
public ActionResult mymethod()
{
//action method goes here
}

Why do none of my ActionFilters run?

I asked a question earlier today about ActionFilters in ASP.Net MVC. It turned out my problem was really that my ActionFilter is not even running. Among other things I read this article, and I can't find anything he does that I don't.
This is my code:
// The ActionFilter itself
public class TestingIfItWorksAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.TempData["filter"] = "it worked!";
base.OnActionExecuting(filterContext);
}
}
// The Controller Action with the filter applied
[TestingIfItWorks]
public ActionResult Test()
{
var didit = TempData["filter"];
return View();
}
A breakpoint in the filter method is never hit when I debug, and TempData["filter"] holds a null value when the view is rendered.
Why is this not working?
In case it's helpful to anyone using MVC 4/5:
ActionFilters don't run if you get the namespace of your ActionFilterAttribute or IActionFilter wrong: https://stackoverflow.com/a/13710468/188926
Use System.Web.Http.Filters for Web API, System.Web.Mvc for standard MVC actions.
As in the question, the filter attribute will simply be ignored (no error) if you get it wrong, which makes it difficult to diagnose.
Based on your comments to another answer
When testing via unit tests, the filter is not invoked. If you want to invoke the filter then you'll need mimic the ControllerActionInvoker. It's probably better, to test the filter itself in isolation, then use reflection to ensure that the filter is applied to your action with the correct attributes. I prefer this mechanism over testing the filter and action in combination.
Original
Surely you need an override on your method otherwise you aren't actually replacing the method on the base class. I would have expected the compiler to complain that you needed either a new or override on it. If you don't include the override keyword, it will behave as if you used new. Since the framework invokes it as an ActionFilterAttribute, this means that your method will never get called.
Quoting from MSDN:
If the method in the derived class is
not preceded by new or override
keywords, the compiler will issue a
warning and the method will behave as
if the new keyword were present.
In addition to what tvanofosson said, your action method isn't actually rendering anything to the view. Does your view have a <%=TempData["Filter"].ToString()%> statement or something similar?

Resources