简体   繁体   中英

error: Make sure that the controller has a parameterless public constructor webapi

I am using webapi, unity, and mvc. I am getting the error "Make sure that the controller has a parameterless public constructor". I have seen treads on similar problems but still can't get it to work. I have installed unity.webapi and seem to have all the necessary references:

  • Microsoft.Practices.Unity - runtime: v4.0.30319, version: 3.5.0.0
  • Microsoft.Practices.Unity.Mvc - runtime: v4.0.30319, version: 3.5.0.0
  • Unity.WebApi - runtime: v4.0.30319, version: 5.1.0.0
  • System.Web.Http - runtime: v4.0.30319, version: 5.2.2.0
  • System.Web.Mvc - runtime: v4.0.30319, version: 5.2.2.0

I verified everything matches what is on this site:

http://www.asp.net/mvc/overview/releases/how-to-upgrade-an-aspnet-mvc-4-and-web-api-project-to-aspnet-mvc-5-and-web-api-2

Here is what I have:

Bootstrapper:

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.RegisterType<IDatabaseFactoryHouseDB, DatabaseFactoryHouseDB>(new HierarchicalLifetimeManager());
        container.RegisterType<UnitOfWorkHouseDB>();

        // repositories
        container.RegisterType<IEmployeeRepository, EmployeeRepository>();

        // services
        container.RegisterType<IEmployeeService, EmployeeService>();
        RegisterTypes(container);

        return container;
    }
    public static void RegisterTypes(IUnityContainer container) { }
}

Global.asax:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        Database.SetInitializer<HouseDBContext>(null);

        Bootstrapper.Initialise();
        //required for setting routes in the attributes of a controller method
        GlobalConfiguration.Configuration.EnsureInitialized();
    }
}

Api controller:

public class EmployeeApiController : ApiController
{
    private readonly IEmployeeService employeeService;

    public EmployeeApiController(IEmployeeService employeeService)
    {
        this.employeeService = employeeService;
    }

    // rest of controller
}

WebApiConfig:

    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // use json strings as the default return value for the app
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

        // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
        // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
        // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
        //config.EnableQuerySupport();

        // To disable tracing in your application, please comment out or remove the following line of code
        // For more information, refer to: http://www.asp.net/web-api
        config.EnableSystemDiagnosticsTracing();
    }

UnityConfig:

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
    }
}

Not sure what I am missing.

Edit: I noticed I had a UnityConfig class in my App_Start folder. After looking into the comment by Sarathy, I realized it wasn't be called. I commented out my bootstrapper initialization in the global.asax and added the line UnityConfig.RegisterComponents(), so now my global.asax looks like this:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        UnityConfig.RegisterComponents();  //  <--- added
        AreaRegistration.RegisterAllAreas();

        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        Database.SetInitializer<HouseDBContext>(null);

        //Bootstrapper.Initialise(); <-- not using bootstrapper anymore
        //required for setting routes in the attributes of a controller method
        GlobalConfiguration.Configuration.EnsureInitialized();
    }
}

and my UnityConfig looks like this:

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();    
        container.RegisterType<IDatabaseFactoryHouseDB, DatabaseFactoryHouseDB>(new HierarchicalLifetimeManager());
        //container.RegisterType<IUnitOfWork>();
        container.RegisterType<UnitOfWorkHouseDB>();

        // repositories
        container.RegisterType<IEmployeeRepository, EmployeeRepository>();

        // services
        container.RegisterType<IEmployeeService, EmployeeService>();

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}

Yet I still get the parameterless constructor error. What is funny is even though I have added a parameterless constructor:

    public class EmployeeApiController : ApiController
    {
        private readonly IEmployeeService employeeService;

        public EmployeeApiController()
            : base()
        {
        } 

        public EmployeeApiController(IEmployeeService employeeService)
        {
            this.employeeService = employeeService;
        }
}

I still get the error when using the unityconfig approach. With bootstrapper, I didn't get the error but my services were not initialized.

I am totally confused. Somehow I feel I am mixing MVC and WebApi and things are not resolving correctly...

EDIT 2:

I looked at the inner exception of my parameterless constructor error and noticed it is mentioning my IUnitOfWork class:

"Resolution of the dependency failed, type = \\"AngularMVC.Controllers.EmployeeApiController\\", name = \\"(none)\\".\\r\\nException occurred while: while resolving.\\r\\nException is: InvalidOperationException - The current type, AngularMVC.Models.Interfaces.IUnitOfWork, is an interface and cannot be constructed. Are you missing a type mapping ?\\r\\n-----------------------------------------------\\r\\nAt the time of the exception, the container was:\\r\\n\\r\\n Resolving AngularMVC.Controllers.EmployeeApiController,(none)\\r\\n Resolving parameter \\"employeeService\\" of constructor AngularMVC.Controllers.EmployeeApiController(AngularMVC.Services.IEmployeeService employeeService)\\r\\n Resolving AngularMVC.Services.EmployeeService,(none) (mapped from AngularMVC.Services.IEmployeeService, (none))\\r\\n Resolving parameter \\"unitOfWork\\" of constructor AngularMVC.Services.EmployeeService(AngularMVC.Models.Repositories.IEmployeeRepository employeeRepository, AngularMVC.Models.Interfaces.IUnitOfWork unitOfWork )\\r\\n Resolving AngularMVC.Models.Interfaces.IUnitOfWork,(none)\\r\\n"

which is only this:

public interface IUnitOfWork
{
    void Commit();
}

When I do the following in my UnityConfig:

        container.RegisterType<IUnitOfWork>();
        IUnitOfWork sm = container.Resolve<IUnitOfWork>();

I get the same error stating "The current type, AngularMVC.Models.Interfaces.IUnitOfWork, is an interface and cannot be constructed. Are you missing a type mapping?"

From your code, I can see you are using Unity as your IoC Container. IoC Container will handle the initialization of controller class.

To make IoC container to create a instance of your controller, your controller class needs to have a parameterless public constructor(aka default constructor).

public class EmployeeApiController : ApiController
{
    private readonly IEmployeeService employeeService;

    public EmployeeAPIController() : base()
    {
    }

    public EmployeeApiController(IEmployeeService employeeService)
    {
        this.employeeService = employeeService;
    }
}

UPDATE 1: 18 Feb 2015 From your code I have not seen a implementation of IUnitOfWork interface. The unit of work is pattern that is widely used in domain central modeling. Normally, unit of work pattern is used with repository pattern together. The purpose of of unit of work, is to make multiple repository can working on a same database context.

From your code, you register

//container.RegisterType<IUnitOfWork>();
container.RegisterType<UnitOfWorkHouseDB>();

However, I think you should have register code like this: (I assume UnitOfWorkHouseDB is the implementation of IUnitOfWork)

container.RegisterType<IUnitOfWork, UnitOfWorkHouseDB>();

Which is similar as: (EmployeeRepository is the implementation of IEmployeeRepository)

// repositories
container.RegisterType<IEmployeeRepository, EmployeeRepository>();

Normally, when I use unit of work and repository pattern, I will do following structure:

IUnitOfWork interface

public interface IUnitOfWork
{
    void Commit();
}

IUnitOfWork implementation:

public class UnitOfWork : IUnitOfWork
{
    //DBContext could your own db context, or a interface, like IDatabaseFactoryHouseDB 
    private DBContext _ctx;

    public UnitOfWork(DbContext ctx)
    {
        _ctx = ctx;
    }

    private IEmployeeRepository _EmployeeRepository;
    public IEmployeeRepository EmployeeRepository
    {
        get { return _EmployeeRepository ?? (_EmployeeRepository = new EmployeeRepository(_ctx)); }
    }

    private ICustomerRepository _CustomerRepository;
    public ICustomerRepository CustomerRepository
    {
        get { return _CustomerRepository ?? (_CustomerRepository = new CustomerRepository(_ctx)); }
    }

    public void Commit()
    {
        _ctx.SaveChange();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM