Eu segui este tutorial que funcionou muito bem, até que modifiquei meu DbContext
para ter um construtor adicional. Agora estou tendo problemas com a resolução e não tenho certeza do que fazer para corrigir isso. Existe uma maneira fácil de forçá-lo a agarrar o construtor sem parâmetros ou estou abordando isso incorretamente?
DbContext
com dois construtores:
public class DashboardDbContext : DbContext
{
public DashboardDbContext() : base("DefaultConnection") { }
public DashboardDbContext(DbConnection dbConnection, bool owns)
: base(dbConnection, owns) { }
}
SiteController
construtor:
private readonly IDashboardRepository _repo;
public SiteController(IDashboardRepository repo)
{
_repo = repo;
}
Repositório:
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);
Erro da chamada WebApi:
System.InvalidOperationException: Ocorreu um erro ao tentar criar um controlador do tipo 'SiteController'. Certifique-se de que o controlador tenha um construtor público sem 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: Tipo 'Dashboard.Web.Controllers.SiteController' não tem um construtor padrão.
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)
O tutorial foi ótimo e tem funcionado bem para mim até eu adicionar o segundo construtor.
fonte
SiteController
é isso que deve ter um construtor sem parâmetros, nãoDashboardDbContext
.SiteController
?DbContext
no repositório?Respostas:
O que está acontecendo é que você está mordido por esse problema . Basicamente, o que aconteceu é que você não registrou seus controladores explicitamente em seu contêiner. O Unity tenta resolver os tipos concretos não registrados para você, mas como não consegue resolver (causado por um erro em sua configuração), ele retorna nulo. Ele é forçado a retornar nulo, porque a API da Web o força a fazê-lo devido ao
IDependencyResolver
contrato. Como o Unity retorna nulo, a API Web tentará criar o próprio controlador, mas, como não tem um construtor padrão, lançará a exceção "Certifique-se de que o controlador possui um construtor público sem parâmetros". Essa mensagem de exceção é enganosa e não explica a causa real.Você teria visto uma mensagem de exceção muito mais clara se registrasse seus controladores explicitamente, e é por isso que você deve sempre registrar todos os tipos de raiz explicitamente.
Mas é claro, o erro de configuração vem de você adicionar o segundo construtor ao seu
DbContext
. O Unity sempre tenta escolher o construtor com mais argumentos, mas não tem ideia de como resolver esse construtor específico.Portanto, a verdadeira causa é que você está tentando usar os recursos de fiação automática do Unity para criar o
DbContext
.DbContext
é um tipo especial que não deve ser conectado automaticamente. É um tipo de estrutura e você deve, portanto, voltar a registrá-lo usando um representante de fábrica :fonte
IDependencyResolver
mas apenas um personalizadoIControllerActivator
.No meu caso, foi por causa de uma exceção dentro do construtor da minha dependência injetada (em seu exemplo - dentro do construtor DashboardRepository). A exceção foi detectada em algum lugar dentro da infraestrutura MVC. Eu descobri isso depois de adicionar logs em locais relevantes.
fonte
Make sure that the controller has a parameterless public constructor.
mas é bem possível que a dependência esteja configurada, mas uma exceção nas entranhas impediu que isso fosse resolvido.Eu tive o mesmo problema e resolvi fazendo alterações no arquivo UnityConfig.cs. Para resolver o problema de dependência no arquivo UnityConfig.cs, você deve adicionar:
fonte
Às vezes, porque você está resolvendo sua interface em ContainerBootstraper.cs, é muito difícil detectar o erro. No meu caso, ocorreu um erro ao resolver a implementação da interface que injetei no controlador da API. Não consegui encontrar o erro porque resolvi a interface em meu bootstraperContainer assim:
container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
então adicionei a seguinte linha em meu contêiner de bootstrap:
container.RegisterType<MyController>();
então, quando eu compilar o projeto, o compilador reclamou e parou na linha acima e mostrou o erro .fonte
Eu tive o mesmo problema. Pesquisei no Google por dois dias. Por fim notei sem querer que o problema era modificador de acesso do construtor do Controller. Não coloquei a
public
palavra-chave por trás do construtor do Controlador.Acrescento esta experiência como outra resposta, talvez outra pessoa tenha cometido um erro semelhante.
fonte
Se você tiver uma interface em seu controlador
Você deve registrá-los no contêiner de injeção de dependência.
fonte
Recebi este erro quando defini acidentalmente uma propriedade como um tipo de objeto específico, em vez do tipo de interface que defini no UnityContainer.
Por exemplo:
Definindo UnityContainer:
SiteController (o caminho errado - observe o tipo de repo):
SiteController (da maneira certa):
fonte
Se você estiver usando UnityConfig.cs para resistir aos mapeamentos do seu tipo, como abaixo.
Você tem que informar
**webApiConfig.cs**
sobre o Containerfonte
No meu caso, a Unidade acabou sendo uma pista falsa. Meu problema era resultado de diferentes projetos direcionados a diferentes versões do .NET. O Unity foi configurado corretamente e tudo foi registrado corretamente no contêiner. Tudo compilado bem. Mas o tipo estava em uma biblioteca de classes e a biblioteca de classes foi configurada para o .NET Framework 4.0. O projeto WebApi usando Unity foi definido para o .NET Framework 4.5. Alterar a biblioteca de classes para também direcionar 4.5 resolveu o problema para mim.
Eu descobri isso comentando o construtor DI e adicionando o construtor padrão. Comentei os métodos do controlador e fiz com que lançassem NotImplementedException. Confirmei que poderia alcançar o controlador e, ao ver minha NotImplementedException, me disse que estava instanciando o controlador corretamente. Em seguida, no construtor padrão, instanciei manualmente a cadeia de dependência em vez de depender do Unity. Ele ainda compilou, mas quando o executei, a mensagem de erro voltou. Isso confirmou para mim que ainda recebia o erro mesmo quando o Unity estava fora de cogitação. Por fim, comecei na parte inferior da corrente e fui subindo, comentando uma linha de cada vez e testando novamente até não receber mais a mensagem de erro. Isso me apontou na direção da classe ofensiva e, a partir daí, descobri que ela estava isolada em uma única assembléia.
fonte