He seguido este tutorial que ha funcionado muy bien, hasta que modifiqué mi DbContext
para tener un constructor adicional. Ahora tengo problemas con la resolución y no estoy seguro de qué hacer para solucionarlo. ¿Hay una manera fácil de forzarlo a tomar el constructor sin parámetros o me estoy acercando a esto incorrectamente?
DbContext
con dos constructores:
public class DashboardDbContext : DbContext
{
public DashboardDbContext() : base("DefaultConnection") { }
public DashboardDbContext(DbConnection dbConnection, bool owns)
: base(dbConnection, owns) { }
}
SiteController
constructor:
private readonly IDashboardRepository _repo;
public SiteController(IDashboardRepository repo)
{
_repo = repo;
}
Repositorio:
DashboardDbContext _context;
public DashboardRepository(DashboardDbContext context)
{
_context = context;
}
UnityResolver
código:
public class UnityResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = _container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
_container.Dispose();
}
}
WebApiConfig:
var container = new UnityContainer();
container.RegisterType<IDashboardRepository, DashboardRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
Error de la llamada de WebApi:
System.InvalidOperationException: se produjo un error al intentar crear un controlador de tipo 'SiteController'. Asegúrese de que el controlador tenga un constructor público sin parámetros.
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()
InnerException: System.ArgumentException: el tipo 'Dashboard.Web.Controllers.SiteController' no tiene un constructor predeterminado.
at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
El tutorial fue genial y me ha funcionado bien hasta que agregué el segundo constructor.
fuente
SiteController
es lo que debe tener un constructor sin parámetros, noDashboardDbContext
.SiteController
?DbContext
en el repositorio?Respuestas:
Lo que pasa es que te muerde este problema . Básicamente, lo que sucedió es que no registró sus controladores explícitamente en su contenedor. Unity intenta resolver tipos concretos no registrados por usted, pero como no puede resolverlo (causado por un error en su configuración), devuelve nulo. Se ve obligado a devolver un valor nulo, porque la API web lo obliga a hacerlo debido al
IDependencyResolver
contrato. Dado que Unity devuelve un valor nulo, la API web intentará crear el controlador en sí mismo, pero como no tiene un constructor predeterminado, lanzará la excepción "Asegúrese de que el controlador tenga un constructor público sin parámetros". Este mensaje de excepción es engañoso y no explica la causa real.Habría visto un mensaje de excepción mucho más claro si registró sus controladores explícitamente, y es por eso que siempre debe registrar todos los tipos de raíz explícitamente.
Pero, por supuesto, el error de configuración proviene de que agregas el segundo constructor a tu
DbContext
. Unity siempre intenta elegir el constructor con más argumentos, pero no tiene idea de cómo resolver este constructor en particular.Entonces, la causa real es que está tratando de usar las capacidades de cableado automático de Unity para crear el
DbContext
.DbContext
es un tipo especial que no debe conectarse automáticamente. Es un tipo de marco y, por lo tanto, debe volver a registrarlo utilizando un delegado de fábrica :fuente
IDependencyResolver
solo usa una personalizada en suIControllerActivator
lugar.En mi caso, fue debido a una excepción dentro del constructor de mi dependencia inyectada (en su ejemplo, dentro del constructor DashboardRepository). La excepción se detectó en algún lugar dentro de la infraestructura MVC. Encontré esto después de agregar registros en lugares relevantes.
fuente
Make sure that the controller has a parameterless public constructor.
pero es muy posible que la dependencia esté configurada, pero una excepción en las entrañas ha impedido que se resuelva.Tuve el mismo problema y lo resolví haciendo cambios en el archivo UnityConfig.cs.Para resolver el problema de dependencia en el archivo UnityConfig.cs, debe agregar:
fuente
A veces, debido a que está resolviendo su interfaz en ContainerBootstraper.cs, es muy difícil detectar el error. En mi caso hubo un error al resolver la implementación de la interfaz que inyecté al controlador de la API. No pude encontrar el error porque resolví la interfaz en mi bootstraperContainer de esta manera:
container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
luego agregué la siguiente línea en mi contenedor de bootstrap:
container.RegisterType<MyController>();
así que cuando compilé el proyecto, el compilador se quejó y se detuvo en la línea anterior y mostró el error .fuente
Yo tuve el mismo problema. Lo busqué en Google durante dos días. Por fin noté accidentalmente que el problema era el modificador de acceso del constructor del Controlador. No puse la
public
palabra clave detrás del constructor del controlador.Agrego esta experiencia como otra respuesta, tal vez alguien más cometió un error similar.
fuente
Si tiene una interfaz en su controlador
Debe registrarlos en el contenedor de Inyección de dependencia.
fuente
Tengo este error cuando definí accidentalmente una propiedad como un tipo de objeto específico, en lugar del tipo de interfaz que definí en UnityContainer.
Por ejemplo:
Definición de UnityContainer:
SiteController (de forma incorrecta - aviso del tipo de repositorio):
SiteController (la forma correcta):
fuente
Si está utilizando UnityConfig.cs para resistir las asignaciones de su tipo como se muestra a continuación.
Tienes que informar
**webApiConfig.cs**
sobre Containerfuente
En mi caso, Unity resultó ser una pista falsa. Mi problema fue el resultado de diferentes proyectos dirigidos a diferentes versiones de .NET. Unity se configuró correctamente y todo se registró correctamente en el contenedor. Todo compilado bien. Pero el tipo estaba en una biblioteca de clases y la biblioteca de clases estaba configurada como destino .NET Framework 4.0. El proyecto WebApi que usa Unity se configuró para .NET Framework 4.5. Cambiar la biblioteca de clases para apuntar también a 4.5 solucionó el problema para mí.
Descubrí esto comentando el constructor DI y agregando el constructor predeterminado. Comenté los métodos del controlador y les pedí que lanzaran NotImplementedException. Confirmé que podía llegar al controlador y, al ver mi NotImplementedException, me dijo que estaba creando una instancia del controlador bien. A continuación, en el constructor predeterminado, he creado una instancia manual de la cadena de dependencia en lugar de confiar en Unity. Todavía se compiló, pero cuando lo ejecuté, volvió el mensaje de error. Esto me confirmó que seguía recibiendo el error incluso cuando Unity estaba fuera de escena. Finalmente, comencé en la parte inferior de la cadena y fui subiendo, comentando una línea a la vez y volviendo a probar hasta que ya no recibí el mensaje de error. Esto me apuntó en la dirección de la clase infractora, y desde allí me di cuenta de que estaba aislada a una sola asamblea.
fuente