Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve a dynamic controller and action method in ASP.NET MVC?

In Asp.net MVC the url structure goes like

http://example.com/{controller}/{action}/{id}

For each "controller", say http://example.com/blog, there is a BlogController.

But my {controller} portion of the url is not decided pre-hand, but it is dynamically determined at run time, how do I create a "dynamic controller" that maps anything to the same controller which then based on the value and determines what to do?

Same thing with {action}, if the {action} portion of my url is also dynamic, is there a way to program this scenario?

like image 238
Ray Avatar asked Jul 21 '10 20:07

Ray


People also ask

What are action methods in ASP.NET MVC?

ASP.NET MVC Action Methods are responsible to execute requests and generate responses to it. By default, it generates a response in the form of ActionResult. Actions typically have a one-to-one mapping with user interactions.

What are action methods in controller?

An action (or action method ) is a method on a controller that handles incoming requests. Controllers provide a logical means of grouping similar actions together, allowing common sets of rules (e.g. routing, caching, authorization) to be applied collectively. Incoming requests are mapped to actions through routing.

How many types of action methods are there in MVC?

Figure 2: Types of Action Result There are two methods in Action Result. One is ActionResult() and another one is ExecuteResult().

Can action method be static in MVC?

- Action method cannot be a static method. ActionResult is a base class of all the result type which returns from Action method.


1 Answers

Absolutely! You'll need to override the DefaultControllerFactory to find a custom controller if one doesn't exist. Then you'll need to write an IActionInvoker to handle dynamic action names.

Your controller factory will look something like:

public class DynamicControllerFactory : DefaultControllerFactory {     private readonly IServiceLocator _Locator;      public DynamicControllerFactory(IServiceLocator locator)     {         _Locator = locator;     }      protected override Type GetControllerType(string controllerName)     {         var controllerType = base.GetControllerType(controllerName);             // if a controller wasn't found with a matching name, return our dynamic controller         return controllerType ?? typeof (DynamicController);     }      protected override IController GetControllerInstance(Type controllerType)     {         var controller = base.GetControllerInstance(controllerType) as Controller;          var actionInvoker = _Locator.GetInstance<IActionInvoker>();         if (actionInvoker != null)         {             controller.ActionInvoker = actionInvoker;         }          return controller;     } } 

Then your action invoker would be like:

public class DynamicActionInvoker : ControllerActionInvoker {     private readonly IServiceLocator _Locator;      public DynamicActionInvoker(IServiceLocator locator)     {         _Locator = locator;     }      protected override ActionDescriptor FindAction(ControllerContext controllerContext,                                                    ControllerDescriptor controllerDescriptor, string actionName)     {             // try to match an existing action name first         var action = base.FindAction(controllerContext, controllerDescriptor, actionName);         if (action != null)         {             return action;         }  // @ray247 The remainder of this you'd probably write on your own...         var actionFinders = _Locator.GetAllInstances<IFindAction>();         if (actionFinders == null)         {             return null;         }          return actionFinders             .Select(f => f.FindAction(controllerContext, controllerDescriptor, actionName))             .Where(d => d != null)             .FirstOrDefault();     } } 

You can see a lot more of this code here. It's an old first draft attempt by myself and a coworker at writing a fully dynamic MVC pipeline. You're free to use it as a reference and copy what you want.

Edit

I figured I should include some background about what that code does. We were trying to dynamically build the MVC layer around a domain model. So if your domain contained a Product class, you could navigate to products\alls to see a list of all products. If you wanted to add a product, you'd navigate to product\add. You could go to product\edit\1 to edit a product. We even tried things like allowing you to edit properties on an entity. So product\editprice\1?value=42 would set the price property of product #1 to 42. (My paths might be a little off, I can't recall the exact syntax anymore.) Hope this helps!

like image 66
Ryan Avatar answered Sep 19 '22 13:09

Ryan