t4mvc : Cannot inherit a controller class which has no default constructor?
Asked Answered
N

3

9

I am using T4MVC with MVC2.

I have the following building blocks:

  1. A simple entity interface which defines that every POCO entity must have a long Id property:

    public interface IEntity
    {
        public long Id;
    }
    
  2. A simple POCO class which implements the IEntity interface and has some string properties:

    public class CD : IEntity
    {
        public long Id { get; set; }
    
        public long Name { get; set; }
    }
    
  3. A base controller:

    public abstract class EntityController<T> : Controller where T : class, global::IEntity
    {
        public EntityController(IEntityManager<T> manager);
    }
    
  4. I use this base controller in my CDController (where CDManager implements the IEntityManager interface, which is a UnitOfWork pattern to add CRUD functionality):

    public partial class CDController : EntityController<CD>
    {
        public CDController() : base(new CDManager()) { }
    }
    

When I run my t4 template, this code is generated:

namespace MyApp.Web.Controllers {
    public partial class CDController {
        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
        protected CDController(Dummy d) { }

But this gives me an error during compilation:

MyApp.EntityController<CD> does not contain a constructor that takes 0 arguments

How can I solve this?

Nebuchadnezzar answered 18/7, 2011 at 9:34 Comment(5)
Lot's of external things being referred. What's IEntity, CD, CDManager? And doesn't your base need a ctor? Would you be able to provide a minimal repro built over a clean MVC3 app, such that I could easily try to repro it? I'm sure we can then find a fix or workaround.Hollywood
David, I've added some more details. Please review.Nebuchadnezzar
I'm still confused. How can the CdController ctor have base(new CDManager()) when EntityController<T> doesn't have a matching controller?Hollywood
Added more details on EntityControllerNebuchadnezzar
Having the same issue ... Can't get T4MVC to generate correct definition where I have a generic controller (for reuse in various projects) that gets inherited in each project just so it can be linked with MVC.{ControllerName}.{Action}Vilma
V
7

I wanted by controller base class to be abstract and it's constructor protected and parametrized. Got around this issue by adding a blank constructor to ControllerBase that throws a NotImplementedException.

Doesn't quite feel right but it gets the job done. Only issue is when combined with dependency injection the wrong constructor will be called - since it throws an exception the app will bum out.

Code:

public abstract class ControllerBase : Controller
{
    protected object AlwaysSupply { get; private set; }

    public ControllerBase()
    {
        throw new NotImplementedException();
    }

    public ControllerBase(object alwaysSupply)
    {
        AlwaysSupply = alwaysSupply;
    }
}

This will cause T4MVC to generate compilable code. The fault seems to be it always tries to generate a blank (no parameters) constructor for controller classes.

Hope this helps someone.

Vilma answered 27/6, 2012 at 14:21 Comment(1)
Have you found any workarounds that don't break dependency injection?Tessatessellate
H
2

I see the problem, and it comes down to T4MVC not quite doing the right thing when dealing with generic classes. Normally it would generate a default ctor for it in a partial class, but the fact that it's generic is throwing it off.

You should be able to work around simply by adding a default ctor yourself, e.g.

public abstract partial class EntityController<T> : Controller where T : class, IEntity {
    public EntityController() { }

    // etc...
}
Hollywood answered 19/7, 2011 at 5:59 Comment(0)
S
0

I've noticed something very odd:

I've added the empty constructor to the base class, but without the throw new NotImplementedException(); and it works fine.

But here's the odd thing, when calling the controller if I have an url like /{controller}?params (default action being set to Index in the RouteConfig) the parameterless private controller on the base class is called. But when I have an url like /{controller}/{action}?params then the constructor with parameters is called.

Startling answered 13/11, 2015 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.