1
votes

Hi i tried to move the ApplicationUserManager & ApplicationSignInManager to a base controller so i have have it in every class.

but now i get this error:

[InvalidOperationException: An error occurred when trying to create a controller of type 'Site.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]

full stacktrace below.

In my BaseController i have this:

[Authorize]
public class BaseController : Controller
{
    protected ApplicationSignInManager _signInManager;
    protected ApplicationUserManager _userManager;

    protected IUnitOfWork UnitOfWork { get; set; }
    protected ApplicationUser _CurrentUser;

    public BaseController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
    {
           UserManager = userManager;
           SignInManager = signInManager;
    }

    public ApplicationSignInManager SignInManager
    {
        get
        {
            return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
        }
        private set
        {
            _signInManager = value;
        }
    }

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

    protected IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }
}

And in my HomeController i have this:

public class HomeController : BaseController
{
    public HomeController(IUnitOfWork UnitOfWork)
    {
        this.UnitOfWork = UnitOfWork;
    }

    public ActionResult Index()
    {
        return View("Index");
    }
}

in my Startup.Auth i have this:

namespace Site.App_Start
{
    public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {

            app.CreatePerOwinContext(MoonDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                ExpireTimeSpan = TimeSpan.FromMinutes(10),
                LoginPath = new PathString("/Login"),
                Provider = new CookieAuthenticationProvider
                {

                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });

        }
    }
}

And this is the error im getting:

[InvalidOperationException: An error occurred when trying to create a controller of type 'Site.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +178
System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +76
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +88
System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +191 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +50
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

I Just want to clean up my code a bit and move the managers to a base class, seems like i missed a step

2
I think the problem is in error message. The controller wants a parameterless constructor public HomeController{}. your base controller needs parameters. You might try something like public Homecontroller {mybase(usermanger, etc.. ) }Haim Katz

2 Answers

1
votes

I would make some design changes to make the base controller a little cleaner. You controllers should depend on abstractions and not concretions.

First move the dependencies for your base controller into a simpler abstraction.

public interface IApplicationManager {
    ApplicationSignInManager SignInManager { get; }
    ApplicationUserManager UserManager { get; }
}

you create the implementation to create the managers within there.

Your base controller is then refactored to this:

[Authorize]
public class BaseController : Controller {
    protected ApplicationSignInManager _signInManager;
    protected ApplicationUserManager _userManager;

    protected IUnitOfWork UnitOfWork { get; set; }
    protected ApplicationUser _CurrentUser;

    public BaseController(IApplicationManager appManager) {
        UserManager = appManager.UserManager;
        SignInManager = appManager.SignInManager;
    }

    public ApplicationSignInManager SignInManager {
        get {
            return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
        }
        private set {
            _signInManager = value;
        }
    }

    public ApplicationUserManager UserManager {
        get {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set {
            _userManager = value;
        }
    }

    protected IAuthenticationManager AuthenticationManager {
        get {
            return HttpContext.GetOwinContext().Authentication;
        }
    }
}

The problem with creating base controller with a parameter in constructor is that classes that inherit from it need to make sure to call that base constructor as well. Given that you are using DI then you need to make sure that the necessary dependencies are also passed to decedent classes.

public class HomeController : BaseController {
    public HomeController(IUnitOfWork UnitOfWork, IApplicationManager appManager)
        : base(appManager) {
        this.UnitOfWork = UnitOfWork;
    }

    public ActionResult Index() {
        return View("Index");
    }
} 

Finally make sure that the dependency resolver (IDependencyResolver) is aware of how to resolve your IApplicationManager to its implementation, ApplicationSignInManager and ApplicationUserManager otherwise you will get the same parameterless constructor errors. You tagged the question with Ninject so you should start looking there as you only setup OWIN DI.

0
votes

Your BaseController doesn't have a parameterless constructor. When you do HomeController : BaseController you are asking for a parameterless constructor of BaseController.

To fix this, you either need another constructor in BaseController that sets the parameters or you need to do HomeController : BaseController(p1, p2) (not in front of Visual Studio right now so that might not be 100% correct code, just did it from memory)