Postępowałem zgodnie z tym samouczkiem, który działał świetnie, dopóki nie zmodyfikowałem mojego, DbContext
aby mieć dodatkowego konstruktora. Mam teraz problemy z rozdzielczością i nie wiem, co zrobić, aby to naprawić. Czy istnieje łatwy sposób, aby zmusić go do pobrania konstruktora bez parametrów, czy podchodzę do tego niepoprawnie?
DbContext
z dwoma konstruktorami:
public class DashboardDbContext : DbContext
{
public DashboardDbContext() : base("DefaultConnection") { }
public DashboardDbContext(DbConnection dbConnection, bool owns)
: base(dbConnection, owns) { }
}
SiteController
konstruktor:
private readonly IDashboardRepository _repo;
public SiteController(IDashboardRepository repo)
{
_repo = repo;
}
Magazyn:
DashboardDbContext _context;
public DashboardRepository(DashboardDbContext context)
{
_context = context;
}
UnityResolver
kod:
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);
Błąd wywołania WebApi:
System.InvalidOperationException: Wystąpił błąd podczas próby utworzenia kontrolera typu „SiteController”. Upewnij się, że kontroler ma konstruktora publicznego bez parametrów.
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: Typ „Dashboard.Web.Controllers.SiteController” nie ma domyślnego konstruktora.
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)
Samouczek był świetny i działał dobrze, dopóki nie dodałem drugiego konstruktora.
źródło
SiteController
to musi mieć konstruktor bez parametrów, a nieDashboardDbContext
.SiteController
?DbContext
do repozytorium?Odpowiedzi:
Dzieje się tak, że ten problem cię ugryzł . Zasadniczo zdarzyło się, że nie zarejestrowałeś kontrolerów jawnie w swoim kontenerze. Unity próbuje rozwiązać za Ciebie niezarejestrowane konkretne typy, ale ponieważ nie może ich rozwiązać (z powodu błędu w konfiguracji), zwraca wartość null. Jest zmuszony zwrócić wartość null, ponieważ interfejs API sieci Web wymusza to na podstawie
IDependencyResolver
kontraktu. Ponieważ Unity zwraca wartość null, interfejs API sieci Web spróbuje samodzielnie utworzyć kontroler, ale ponieważ nie ma domyślnego konstruktora, zgłosi wyjątek „Upewnij się, że kontroler ma publiczny konstruktor bez parametrów”. Ten komunikat o wyjątku jest mylący i nie wyjaśnia prawdziwej przyczyny.Widziałbyś znacznie wyraźniejszy komunikat o wyjątku, gdybyś jawnie zarejestrował swoje kontrolery i dlatego zawsze powinieneś jawnie rejestrować wszystkie typy rootów.
Ale oczywiście błąd konfiguracji pochodzi z dodania drugiego konstruktora do pliku
DbContext
. Unity zawsze próbuje wybrać konstruktora z największą liczbą argumentów, ale nie ma pojęcia, jak rozwiązać ten konkretny konstruktor.Więc prawdziwą przyczyną jest to, że próbujesz użyć możliwości automatycznego łączenia Unity, aby utworzyć plik
DbContext
.DbContext
to specjalny typ, którego nie należy łączyć automatycznie. Jest to typ frameworku i dlatego należy cofnąć się do zarejestrowania go przy użyciu delegata fabryki :źródło
IDependencyResolver
aIControllerActivator
zamiast niego użyj niestandardowego .W moim przypadku było to spowodowane wyjątkiem wewnątrz konstruktora mojej wstrzykniętej zależności (w twoim przykładzie - wewnątrz konstruktora DashboardRepository). Wyjątek został przechwycony gdzieś w infrastrukturze MVC. Znalazłem to po dodaniu logów w odpowiednich miejscach.
źródło
Make sure that the controller has a parameterless public constructor.
ale jest całkiem możliwe, że zależność jest skonfigurowana, ale wyjątek głęboko w trzewiach uniemożliwił jej rozwiązanie.Miałem ten sam problem i rozwiązałem go, wprowadzając zmiany w pliku UnityConfig.cs.Aby rozwiązać problem z zależnościami w pliku UnityConfig.cs, musisz dodać:
źródło
Czasami, ponieważ rozwiązujesz swój interfejs w ContainerBootstraper.cs, bardzo trudno jest wychwycić błąd. W moim przypadku wystąpił błąd w rozwiązaniu implementacji interfejsu, który wstrzyknąłem do kontrolera API. Nie mogłem znaleźć błędu, ponieważ rozwiązałem interfejs w moim bootstraperContainerze w następujący sposób:
container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
następnie dodałem następujący wiersz w moim kontenerze bootstrap:
container.RegisterType<MyController>();
więc kiedy kompiluję projekt, kompilator narzekał i zatrzymał się w powyższej linii i pokazał błąd .źródło
Miałem ten sam problem. Wyszukiwałem go w Google przez dwa dni. W końcu przypadkowo zauważyłem, że problemem był modyfikator dostępu konstruktora kontrolera. Nie umieściłem
public
słowa kluczowego za konstruktorem kontrolera.Dodam to doświadczenie jako kolejną odpowiedź, być może ktoś inny popełnił podobny błąd.
źródło
Jeśli masz interfejs w kontrolerze
Musisz zarejestrować je w kontenerze Dependency Injection.
źródło
Wystąpił ten błąd, gdy przypadkowo zdefiniowałem właściwość jako określony typ obiektu, zamiast typu interfejsu, który zdefiniowałem w UnityContainer.
Na przykład:
Definiowanie UnityContainer:
SiteController (zły sposób - typ repozytorium powiadomień):
SiteController (właściwy sposób):
źródło
Jeśli używasz UnityConfig.cs do ochrony mapowań twojego typu, jak poniżej.
Musisz poinformować
**webApiConfig.cs**
o pojemnikuźródło
W moim przypadku Unity okazała się czerwonym śledziem. Mój problem był wynikiem różnych projektów dotyczących różnych wersji .NET. Unity został poprawnie skonfigurowany i wszystko zostało poprawnie zarejestrowane w kontenerze. Wszystko dobrze skompilowane. Ale typ znajdował się w bibliotece klas, a biblioteka klas była ustawiona na platformę .NET Framework 4.0. Projekt WebApi korzystający z Unity został ustawiony jako docelowy .NET Framework 4.5. Zmiana biblioteki klas na docelową 4.5 rozwiązała problem.
Odkryłem to, wykomentowując konstruktor DI i dodając domyślny konstruktor. Zakomentowałem metody kontrolera i kazałem im wyrzucić NotImplementedException. Potwierdziłem, że mogę skontaktować się z kontrolerem, a widząc mój wyjątek NotImplementedException powiedział mi, że instancja kontrolera działa poprawnie. Następnie w domyślnym konstruktorze ręcznie utworzyłem wystąpienie łańcucha zależności zamiast polegać na Unity. Wciąż się skompilował, ale kiedy go uruchomiłem, wrócił komunikat o błędzie. Potwierdziło to dla mnie, że nadal otrzymuję błąd, nawet gdy Unity był poza obrazem. W końcu zacząłem od dołu łańcucha i wspinałem się w górę, komentując jedną linię na raz i ponownie testując, aż nie otrzymałem już komunikatu o błędzie. To skierowało mnie w stronę przestępczej klasy i stamtąd doszedłem do wniosku, że została ona odizolowana do jednego zgromadzenia.
źródło