In asp.net mvc is it possible to make a generic controller?

22,858

Solution 1

If I understand you properly, what you are trying to do, is route all requests for a given Model through a generic controller of type T.

You would like the T to vary based on the Model requested.

You would like /Product/Index to trigger MyController<Product>.Index()

This can be accomplished by writing your own IControllerFactory and implementing the CreateController method like this:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    Type controllerType = Type.GetType("MyController")
                              .MakeGenericType(Type.GetType(controllerName));
    return Activator.CreateInstance(controllerType) as IController;
}

Solution 2

Yes you can, it's fine and I've used them lots myself.

What you need to ensure is that when you inherit from MyController you still end the type name with controller:

public class FooController :  MyController<Foo>
{ 
 ...
}

Solution 3

The default controller factory uses "convention" around controller names when it's trying to find a controller to dispatch the request to. You could override this lookup functionality if you wanted, which could then allow your generic controller to work.

This MSDN article...

http://msdn.microsoft.com/en-us/magazine/dd695917.aspx

... has a good writeup of what's going on.

Solution 4

This is a duplicate of asp.net mvc generic controller which actually contains the correct answer. Jeff Fritz's answer is absolutely not correct. Creating your own IControllerFactory will not get past the limitation in ExpressionHelper.GetRouteValuesFromExpression which is generating the error you are seeing. Implementing your own IControllerFactory will still leave you with errors whenever you call RedirectToAction, BuildUrlFromExpression, ActionLink, RenderAction, BeginForm, any any methods that call those.

What is interesting to me, is that Microsoft's "restriction by convention" is already enforced by the constraint "where TController : Controller" that is placed upon the type in the ExpressionHelper.GetRouteValuesFromExpression method. No generic will ever satisfy the convention validation:

string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
    throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}

unless it is inherited by a class ending in "Controller" because typeof(AnyGeneric).Name will never end with "Controller".

Share:
22,858

Related videos on Youtube

Aaron Palmer
Author by

Aaron Palmer

Hubby. Daddy. Ninja. Developer.

Updated on July 09, 2022

Comments

  • Aaron Palmer
    Aaron Palmer almost 2 years

    I'm attempting to create a generic controller, ie:

    public class MyController<T> : Controller where T : SomeType
    { ... }
    

    However, when I try to use it, I'm running into this error everywhere...

    Controller name must end in 'Controller'

    So, my question, Is it possible to make a generic controller in asp.net mvc?

    Thanks!

    • roryf
      roryf almost 15 years
      What exactly are you trying to achieve through this? When MyController is instantiated it needs to know what T is, either through a subclass or it's contructor. If you want to do that dynamically you'd need to write a ControllerFactory
  • Aaron Palmer
    Aaron Palmer almost 15 years
    I don't want separate Controllers for each type... I want one generic controller to handle many types.
  • Aaron Palmer
    Aaron Palmer almost 15 years
    This is interesting, I'm looking into it. Thanks.
  • Jeff Fritz
    Jeff Fritz almost 15 years
    np... Don't forget, the "Controller" naming convention is a DEFAULT STANDARD.. If you want to instantiate in some other way, do it! Write an IControllerFactory that enforces YOUR standard, not MSFT's
  • billy
    billy almost 13 years
    I'd tried this, and when I got to "public void Edit(Foo Item) {...}", MVC did not understand the type Foo, but the base type I set in the generic class, so all the parameters of the object "Item" were to their initial value !!!
  • mare
    mare over 10 years
    the problem with this is, you will also need generic viewmodels, generic way of binding and filtering, generic validation, this could present quite a feat to implement it
  • johnny 5
    johnny 5 almost 8 years
    @mare for any large api that generic way of binding filter should basically be standard especially for things like CRUD
  • Kappacake
    Kappacake over 3 years
    Is @Iain Holder answer the correct one then in your opinion?
  • FLICKER
    FLICKER about 2 years
    You made my day! This was very helpful. Thank you.