asp.net-mvc - unity - web api inversion of control
error: asegúrese de que el controlador tenga un constructor público sin parámetros webapi (1)
Desde su código, puedo ver que está usando Unity como su contenedor IoC. IoC Container se encargará de la inicialización de la clase de controlador.
Para hacer que el contenedor de IoC cree una instancia de su controlador, su clase de controlador necesita tener un constructor público sin parámetros (también conocido como constructor predeterminado).
public class EmployeeApiController : ApiController
{
private readonly IEmployeeService employeeService;
public EmployeeAPIController() : base()
{
}
public EmployeeApiController(IEmployeeService employeeService)
{
this.employeeService = employeeService;
}
}
ACTUALIZACIÓN 1: 18 de febrero de 2015 De su código no he visto una implementación de la interfaz IUnitOfWork. La unidad de trabajo es un patrón que se usa ampliamente en el modelado central de dominios. Normalmente, el patrón de unidad de trabajo se usa junto con el patrón de repositorio. El propósito de la unidad de trabajo es hacer que un repositorio múltiple pueda trabajar en un mismo contexto de base de datos.
De tu código, te registras
//container.RegisterType<IUnitOfWork>();
container.RegisterType<UnitOfWorkHouseDB>();
Sin embargo, creo que deberías tener un código de registro como este: (Supongo que UnitOfWorkHouseDB es la implementación de IUnitOfWork)
container.RegisterType<IUnitOfWork, UnitOfWorkHouseDB>();
Que es similar a: (EmployeeRepository es la implementación de IEmployeeRepository)
// repositories
container.RegisterType<IEmployeeRepository, EmployeeRepository>();
Normalmente, cuando uso la unidad de trabajo y el patrón de repositorio, haré la siguiente estructura:
Interfaz IUnitOfWork
public interface IUnitOfWork
{
void Commit();
}
Implementación de IUnitOfWork:
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();
}
}
Estoy usando webapi, unity y mvc. Me aparece el error "Asegúrese de que el controlador tenga un constructor público sin parámetros". He visto huellas en problemas similares, pero todavía no puedo hacer que funcione. He instalado unity.webapi y parece tener todas las referencias necesarias:
- Microsoft.Practices.Unity - runtime: v4.0.30319, versión: 3.5.0.0
- Microsoft.Practices.Unity.Mvc - runtime: v4.0.30319, version: 3.5.0.0
- Unity.WebApi - tiempo de ejecución: v4.0.30319, versión: 5.1.0.0
- System.Web.Http - runtime: v4.0.30319, versión: 5.2.2.0
- System.Web.Mvc - runtime: v4.0.30319, versión: 5.2.2.0
Verifiqué que todo coincide con lo que está en este sitio:
Esto es lo que tengo:
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();
}
}
Controlador Api:
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);
}
}
No estoy seguro de lo que me estoy perdiendo.
Editar: noté que tenía una clase UnityConfig en mi carpeta App_Start. Después de mirar el comentario de Sarathy, me di cuenta de que no se llamaba. Comenté la inicialización de bootstrapper en global.asax y agregué la línea UnityConfig.RegisterComponents (), por lo que ahora mi global.asax se ve así:
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();
}
}
y mi UnityConfig se ve así:
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);
}
}
Sin embargo, todavía obtengo el error de constructor sin parámetros. Lo gracioso es que he agregado un constructor sin parámetros:
public class EmployeeApiController : ApiController
{
private readonly IEmployeeService employeeService;
public EmployeeApiController()
: base()
{
}
public EmployeeApiController(IEmployeeService employeeService)
{
this.employeeService = employeeService;
}
}
Aún recibo el error cuando uso el enfoque unityconfig. Con bootstrapper, no recibí el error, pero mis servicios no se inicializaron.
Estoy totalmente confundido. De alguna manera, creo que estoy mezclando MVC y WebApi y las cosas no se están resolviendo correctamente ...
EDICION 2:
Miré la excepción interna de mi error de constructor sin parámetros y me di cuenta de que estaba mencionando mi clase IUnitOfWork:
"Falló la resolución de la dependencia, tipo = /" AngularMVC.Controllers.EmployeeApiController / ", name = /" (none) / ". / R / nExcepción ocurrida mientras: mientras se resolvía. / R / nException es: InvalidOperationException - El tipo actual , AngularMVC.Models.Interfaces.IUnitOfWork, es una interfaz y no se puede construir. ¿Te falta una asignación de tipo ? / R / n ---------------------- ------------------------- / r / nEn el momento de la excepción, el contenedor era: / r / n / r / n Resolviendo AngularMVC. Controllers.EmployeeApiController, (ninguno) / r / n Resolución del parámetro / "employeeService /" del constructor AngularMVC.Controllers.EmployeeApiController (AngularMVC.Services.IEmployeeService employeeService) / r / n Resolución de AngularMVC.Services.EmployeeService, (ninguno) (correlacionado desde AngularMVC.Services.IEmployeeService, (ninguno)) / r / n Resolución del parámetro / "unitOfWork /" del constructor AngularMVC.Services.EmployeeService (AngularMVC.Models.Repositories.IEmployeeRepository employeeRepository, AngularMVC.Models.Interfaces.IUnitOfWork unitOfWork ) / r / n Resolviendo AngularMVC.Models.Interfaces.IUnitOfWork, (none) / r / n "
que es solo esto:
public interface IUnitOfWork
{
void Commit();
}
Cuando hago lo siguiente en mi UnityConfig:
container.RegisterType<IUnitOfWork>();
IUnitOfWork sm = container.Resolve<IUnitOfWork>();
Me sale el mismo error que dice "El tipo actual, AngularMVC.Models.Interfaces.IUnitOfWork, es una interfaz y no se puede construir. ¿Te falta un tipo de mapeo?"