2013-08-14 11 views
5

Mamy projekt napisany w ASP.NET MVC i używamy NInject do wstrzyknięcia repozytoriów do kontrolerów. Obecnie używamy właściwości i Inject-atrybut wstrzyknąć repozytoriów, który działa dość dobrze:Jaki jest najlepszy sposób na wstrzyknięcie repozytoriów do kontrolera ASP.NET

[Inject] 
public IMyRepository MyRepos {get;set;} 

Alternatywnym sposobem wstrzykiwanie byłoby to zrobić „ręcznie” za pomocą NInjectServiceLocator:

var myRepos = NInjectServiceLocatorInstance.Resolve<IMyRepository>(); 

Teraz zastanawiałem się nad następującą: pierwsza metoda wymaga, aby wszystkie repozytoria były umieszczone na górze (niekoniecznie na szczycie, ale jest to najbardziej logiczne miejsce) kontrolera. Za każdym razem, gdy zostanie wysłane żądanie, NInject tworzy instancję każdego repozytorium. Dzieje się tak niezależnie od tego, czy wszystkie repozytoria są rzeczywiście potrzebne w konkretnej Akcji.

Druga metoda pozwala bardziej precyzyjnie kontrolować, które repozytoria są rzeczywiście potrzebne, a tym samym może zaoszczędzić trochę narzutu podczas tworzenia kontrolera. Ale prawdopodobnie musisz również dołączyć kod, aby pobrać to samo repozytorium w wielu miejscach.

Który z nich byłby lepszy? Czy lepiej po prostu mieć garść własności repozytoriów, czy lepiej rozwiązać repozytorium, które jest rzeczywiście niezbędne do wykonania określonego działania, kiedy i gdzie jest ono potrzebne? Czy za wstrzyknięcie "bezużytecznych" repozytoriów nałożono karę wykonania? Czy istnieją (nawet ;-) lepsze rozwiązania?

+0

Wywołanie 'NInjectServiceLocatorInstance.Resolve' to wzorzec o nazwie Service Locator. Dużo o tym pisano na Stackoverflow i w internecie (na przykład jest to [sławny artykuł] (http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)). – Steven

+0

@Steven: Wiem o schemacie i jego zaletach i wadach. Jak już powiedziałem, korzystanie z lokalizatora usług może nadal nie być najlepszym rozwiązaniem, ale czy w tym przypadku byłoby lepiej niż zastrzyk nieruchomości lub konstruktora? – Pieter

+0

Jest to kolejność, w jakiej należy wykonać wstrzyknięcie: Wstrzyknięcie konstruktora, wstrzyknięcie właściwości, fabryki, wstrzyknięcie metody, lokalizator usługi. Wybierz tylko następną opcję, jeśli poprzednia nie jest odpowiednia. – Steven

Odpowiedz

2

Constructor Injection powinien być domyślnym wyborem przy korzystaniu z DI.

Powinieneś zadać sobie pytanie, czy kontroler naprawdę jest zależny od tej konkretnej klasy do pracy w ogóle.

Może być rozwiązaniem dla określonych scenariuszy, jeśli masz tylko określone metody, które wymagają zależności.

nigdy nie używałem Property Injection ale Mark Seeman opisuje to w swojej książce (Dependency Injection in .NET):

PROPERTY wstrzykiwań powinien być stosowany tylko wtedy, gdy klasa jesteś opracowanie ma dobrą LOCAL DEFAULT i nadal chcesz umożliwić dzwoniącym dostarczenie różnych implementacji ZALEŻNOŚCI klasy.

WŁÓKNOŚĆ WTRYSKU najlepiej stosować, gdy ODSTĘPNOŚĆ jest opcjonalna.

UWAGA Istnieją pewne kontrowersje wokół kwestii, czy WTRYSK DO WŁAŚCIWOŚCI wskazuje opcję ZALEŻNOŚCI. Jako ogólną zasadę projektowania interfejsu API, I uważa, że ​​właściwości są opcjonalne, ponieważ można łatwo zapomnieć o przypisaniu im , a kompilator nie narzeka. Jeśli akceptujesz tę zasadę w ogólnym przypadku, musisz także zaakceptować ją w specjalnym przypadku DI. 4

Lokalny domyślny jest opisany jako:

Domyślna implementacja abstrakcją, która jest zdefiniowana w tym samym zespole jako konsumenta.

ile budujesz API Proponuję, aby nie używać wtrysk Property

Gdy wniosek zostanie złożony, NInject instancję za każdym repozytorium. Dzieje się tak niezależnie od tego, czy wszystkie repozytoria są rzeczywiście potrzebne w konkretnej Akcji.

Nie sądzę, trzeba martwić się zbytnio o wydajności podczas korzystania z konstruktora wtrysku

+0

Uwagi te mają dla mnie sens, ale zastanawiam się, czy w tym przypadku może on sprawić, że kod będzie bardziej czytelny, jeśli poprosisz tylko o konieczne repozytoria, które będą wstrzykiwane tam, gdzie są rzeczywiście potrzebne, a nie w konstruktorze lub jako własność. – Pieter

+1

Nie sądzę, że czytelny kod jest oparty na tym, jak zaimplementować DI, DI jest tylko sposobem na utworzenie luźnego sprzężenia w aplikacji, aby twój kod był łatwiejszy w utrzymaniu. Jeśli implementacja jest właściwa –

+0

Zauważ, że wiki Ninject jawnie stwierdza wstrzyknięcie własności, jak opisano w książce Marka Seemana (Dependency Injection w .net) nie jest obsługiwane. –

0

zdecydowanie moim ulubionym sposobem jest:

public class MyController : Controller 
{ 
    public IMyRepository MyRepos {get;set;} 

    public MyController(IMyRepository repo) 
    { 
     MyRepos = repo; 
    } 
} 

Więc można użyć pakietu Nuget, takich jak Ninject.MVC3 (lub MVC4), która ma szczególne wsparcie w tym jądro Ninject wewnątrz własnych klas IoC MVC za

https://github.com/ninject/ninject.web.mvc/wiki/MVC3

Gdy masz Ninject haki, możesz pozwolić mu wykonać pracę przypadkach wstrzyknięcie do konstruktora sterownika, który moim zdaniem jest wiele czystsze.

EDIT:

Ahh, OK. Po przeczytaniu twojego pytania nieco dokładniej, widzę, dokąd zmierzasz. W skrócie, jeśli chcesz wybierać, które klasy repo są instansiated następnie trzeba będzie ręcznie połączyć, na przykład:

var myRepos = NInjectServiceLocatorInstance.Resolve<IMyRepository>();

Nie można skonfigurować Ninject (lub innego IoC AFAIK) selektywnie utworzyć obiektu instancje oparte na aktualnie uruchomionej metodzie. Ten poziom ziarnistości jest prawdziwym przypadkiem, który odczuwam, który można rozwiązać, pisząc własną klasę fabryczną kontrolera, ale to byłaby przesada.

+0

Ma to tę samą wadę, co właściwości, których teraz używam. Jedyną różnicą jest to, że teraz wszystkie repozytoria muszą znajdować się w konstruktorze. – Pieter

3

Wolę zastrzyk Konstruktor:

private readonly IMyRepository _repository; 

public MyController(IMyRepository repository) 
{ 
    _repository = repository; 
} 
  • Wszystkie swoimi zależnościami są wymienione w jednej operacji
  • Twój kontroler nie musi nic wiedzieć o NInject
  • Można unit-przetestować kontroler bez Interwencje NInjects za pomocą odgałęzień bezpośrednio do konstruktora
  • Kontroler ma czystszy kod

NInject lub jakakolwiek inna struktura DI wykona pracę za kulisami i sprawi, że skoncentrujesz się na rzeczywistym problemie, a nie DI.

+0

Ma to tę samą wadę co właściwości, których teraz używam. Jedyną różnicą jest to, że teraz wszystkie repozytoria muszą znajdować się w konstruktorze. – Pieter

+1

Rzeczywiście robi tak, ale zarządzając swoim zasięgiem repozytoriów (InRequestScope) na przykład będą one tworzone tylko raz na żądanie. Moim zdaniem czystość i łatwość konserwacji kodu przeważa nad niepotrzebnym tworzeniem obiektów. Jeśli twoje repozytoria są w rzeczywistości czystymi repozytoriami, wówczas narzut na twórczość obiektu będzie bardzo mały. Zmagałem się z tym samym rodzajem problemu (http://stackoverflow.com/questions/18203401/ninject-is-it-possible-to-have-parent-object-in-singletonscope-and-child-in-tra) i zdecydowałem to była mikrooptymalizacja. –

+0

Wszystkie iniekcje są oczywiście w zasięgu żądania. Możesz mieć rację, że jest to mikrooptymalizacja pod względem wydajności na poziomie czynników zewnętrznych. Może jednak sprawić, że kod stanie się bardziej czytelny, ponieważ repozytoria są wstrzykiwane tylko tam, gdzie są rzeczywiście potrzebne. – Pieter

Powiązane problemy