29

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!

Aaron Palmer
  • 8,912
  • 9
  • 48
  • 77
  • 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 – roryf May 11 '09 at 17:14

5 Answers5

40

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;
}
Jim Wolff
  • 5,052
  • 5
  • 34
  • 44
Jeff Fritz
  • 9,821
  • 7
  • 42
  • 52
  • This is interesting, I'm looking into it. Thanks. – Aaron Palmer May 11 '09 at 17:39
  • 1
    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 – Jeff Fritz May 11 '09 at 18:14
  • 1
    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 – mare Oct 27 '13 at 10:48
  • @mare for any large api that generic way of binding filter should basically be standard especially for things like CRUD – johnny 5 Jul 07 '16 at 17:33
10

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>
{ 
 ...
}
Iain Holder
  • 14,172
  • 10
  • 66
  • 86
  • 1
    I don't want separate Controllers for each type... I want one generic controller to handle many types. – Aaron Palmer May 11 '09 at 17:38
  • 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 !!! – billy May 17 '11 at 14:36
  • 2
    You made my day! This was very helpful. Thank you. – FLICKER Apr 21 '22 at 03:22
1

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".

Community
  • 1
  • 1
DaveMorganTexas
  • 847
  • 10
  • 13
1

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.

Martin Peck
  • 11,440
  • 2
  • 42
  • 69
0

If i was you, i'd get the MVC source and create a test MVC project with the source code so you can examine where the exception is generated and see what you can do about your generic idea and the enforced "*controller" naming convention.

Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79