2016-11-21 15 views
6

Mam kontrolera ASP .Net Web API, który chcę wziąć 2 parametry. Pierwszy to kontekst EF, a drugi interfejs buforujący. Jeśli mam tylko kontekst EF konstruktor jest wywoływana, ale kiedy dodać interfejs buforowania pojawia się błąd:Wstrzyknięcie do konstruktora z 2 parami nie działa

An error occurred when trying to create a controller of type 'MyV1Controller'. Make sure that the controller has a parameterless public constructor.

private MyEntities dbContext; 
private IAppCache cache; 

public MyV1Controller(MyEntities ctx, IAppCache _cache) 
{ 
    dbContext = ctx; 
    cache = _cache; 
} 

Moje UnityConfig.cs

public static void RegisterTypes(IUnityContainer container) 
{ 
    // TODO: Register your types here 
    container.RegisterType<MyEntities, MyEntities>(); 
    container.RegisterType<IAppCache, CachingService>(); 
} 

Spodziewam się, że podmiot teraz wie o obydwu typach, gdy zostanie wysłane żądanie dla funkcji MyV1Controller, powinno być możliwe utworzenie instancji, ponieważ konstruktor przyjmuje typy, o których wie, ale tak nie jest. Każdy pomysł, dlaczego?

[EDIT] Zauważ, że tworzę własną klasę (IConfig) i zarejestrował go i dodać go do konstruktora i to działało, ale gdy próbuję dodać IAppCache do mojego konstruktora i złożyć wniosek do API I dostaję błąd informujący mnie, że nie może zbudować mojej klasy kontrolera. Jedyną różnicą, którą widzę jest IAppCache, nie jest w obszarze nazw moich projektów, ponieważ jest to klasa strony trzeciej, ale nie powinno to mieć znaczenia z tego, co rozumiem.

Oto konstruktorów dla CachingService

public CachingService() : this(MemoryCache.Default) { } 

public CachingService(ObjectCache cache) { 
    if (cache == null) throw new ArgumentNullException(nameof(cache)); 
    ObjectCache = cache; 
    DefaultCacheDuration = 60*20; 
} 
+0

jest rejestracja klasa ma być pojedyncza? Sprawdź także 'Implementacja IAppCache'' CachingService', aby upewnić się, że klasa nie rzuca żadnego wyjątku po zainicjowaniu. ten wyjątek bez parametrów jest domyślnym komunikatem, gdy wystąpi błąd podczas próby utworzenia kontrolerów. – Nkosi

+0

Jakie są zależności 'CachingService' Wspominasz, że jest to interfejs/klasa innego producenta. może wymagać zależności, o której kontener nie wie. – Nkosi

+0

Wykorzystuje MemoryCache.Default: https://github.com/alastairtree/LazyCache/blob/master/LazyCache/CachingService.cs – user441521

Odpowiedz

9

Sprawdź realizację CachingServiceIAppCache aby upewnić się, że klasa nie rzuca żadnego wyjątku, gdy zainicjowany. ten wyjątek bez parametrów jest domyślnym komunikatem, gdy wystąpi błąd podczas próby utworzenia kontrolerów. Nie jest to bardzo przydatny wyjątek, ponieważ nie wskazuje dokładnie, jaki był prawdziwy błąd.

Podałeś, że jest to interfejs/klasa innego producenta. Może to być żądanie zależności, o której nie wie kontener.

Odwoływanie Unity Framework IoC with default constructor

Unity jest wywołanie konstruktora z większości parametrów, które w tym przypadku jest ...

public CachingService(ObjectCache cache) { ... } 

W pojemniku nie wiedzą nic o ObjectCache to minie w null które zgodnie z kod w konstruktorze rzuci wyjątek.

UPDATE:

Dodawanie to z uwagi, gdyż może okazać się przydatne dla innych.

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default)); 

Aby uzyskać więcej informacji, przejdź tutaj Register Constructors and Parameters.

+0

Jest to realizacja: CachingService publicznego(): to (MemoryCache.Default) { } CachingService publicznych (ObjectCache cache) { if (cache == null) throw new ArgumentNullException (nameof (cache)); ObjectCache = cache; DefaultCacheDuration = 60 * 20; } – user441521

+0

No cóż, zgaduję, że 'cache == null' to' true'. – Nkosi

+0

Jeśli utworzę instancję obiektu CachingService() w UnityConfig: RegisterTypes(), to nie jest null, więc nie widzę powodu, dla którego byłby on pusty, gdy mój kontroler zostanie utworzony w późniejszym etapie życia aplikacji. Czy istnieje jakiś sposób, aby podłączyć się do Unity podczas wykonywania tych obiektów dla kontrolera, aby uzyskać lepszy wygląd? – user441521

3

Większość kontenerów DI podczas próby rozstrzygnięcia typu zawsze szuka konstruktora z maksymalną liczbą parametrów. Z tego powodu domyślnie wywoływany jest konstruktor CachingService (ObjectCache Cache). Ponieważ instancja ObjectCache nie jest zarejestrowana w Unity, rozwiązanie nie powiedzie się. Po wymuszeniu rejestracji typu w celu wywołania konkretnego konstruktora wszystko działa.

Jeśli więc zarejestrujesz IAppCache i wymusisz wywołanie konstruktora CachingService() - less, to będzie działać zgodnie z oczekiwaniami.

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor()); 

zarejestrowanie go w ten sposób zmusi parametr mniej konstruktora powoływać i wewnętrznie spadnie z powrotem na cokolwiek biblioteka część trzecia chce wykorzystać jako domyślne. W twoim przypadku to będzie

CachingService(): to (MemoryCache.Default)

Innym rozwiązaniem, które zostało wymienione w innych odpowiedzi to zarejestrować i przekazać parametr konstruktora siebie.

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default)); 

Będzie to również działać, ale tutaj bierzesz odpowiedzialność za dostarczenie dostawcy pamięci podręcznej. Moim zdaniem wolałbym, aby biblioteka osoby trzeciej obsługiwała własne wartości domyślne zamiast mnie jako konsumenta przejmującego tę odpowiedzialność.

Proszę spojrzeć na How does Unity.Resolve know which constructor to use?

i kilka dodatkowych informacji dla Niject https://github.com/ninject/ninject/wiki/Injection-Patterns

If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how to resolve.

Powiązane problemy