2012-08-16 12 views
13

Moja aplikacja zawiera wiele zespołów zaplecza (w tym warstwę repozytorium danych Entity Framework), które są współużytkowane przez wiele zespołów front-end (w tym usługę Windows i aplikacja internetowa MVC3).Gdzie zlokalizować moduły Ninject w wielowarstwowej aplikacji?

Moje zrozumienie procesu wiązania Ninject polega na tym, że każdy zestaw zawierający typy wstrzykiwalne powinien również zawierać moduł Ninject, który definiuje domyślne powiązania dla tych typów. Zbiór zdefiniowanych modułów zostałby następnie załadowany do jądra Ninject dla złożeń.

Występują jednak problemy, ponieważ wymagany zakres powiązań nie zawsze jest spójny. Na przykład mój projekt MVC musi powiązać kontekst danych InRequestScope, podczas gdy usługa Windows wiąże się z tą samą klasą InThreadScope.

Oczywiście mogę rozwiązać ten problem, przenosząc wszystkie moduły do ​​projektów frontowych i tym samym utrzymując oddzielne kopie każdego modułu dla każdego scenariusza użycia, ale wydaje się to być hacky, ponieważ duplikuje znaczną część zawartości modułu w wielu projektach. .

Czy istnieje najlepsza praktyka dotycząca tego, gdzie moduły powinny znajdować się w aplikacji wielowarstwowej i jak mogę to pogodzić z potrzebą wiążących różnic między projektami?

Wielkie dzięki za sugestie,

Tim

+0

Zobacz także http://stackoverflow.com/questions/1699197/how-do-you-organise-your-ninject-modules (IIRC to Q to dup, ale jest to najlepsze, co mam na razie) –

+0

Dzięki, Ruben. Masz rację, że między tymi dwoma pytaniami jest wiele wspólnego. Szczególnie podoba mi się twoja sugestia przekazywania parametrów środowiska wykonawczego do modułów, które znajdują się we wspieraniu złożeń - bardzo elastyczna. –

+0

Hmm; to jakiś czas temu (nie próbowałem w żaden sposób wyleczyć mojej odpowiedzi). Mógłbym dosłownie oznaczać * przekazywanie parametrów * z powrotem w ciągu dnia - ogólnie staram się to robić poprzez interfejsy tak bardzo, jak to tylko możliwe. Ponadto było to przed http://manning.com/seemann, co redukuje liczbę pytań, które możesz znaleźć zaskakująco w architekturze DI - dramat def biegnij, nie zadawaj pytań. –

Odpowiedz

12

Aby uzyskać rozwiązanie z pojedynczą aplikacją, zaleca się zarejestrowanie kontenera w projekcie aplikacji (aplikacji internetowej lub projektu usługi sieciowej). W przypadku aplikacji sieciowej będzie to zazwyczaj Global.asax Application_Start. To miejsce, w którym wszystko łączysz, nazywa się Composition Root w terminologii DI.

Dzięki rozwiązaniu wieloprotokołowemu nadal istnieje jeden główny składnik kompozycji na projekt aplikacji. To musi być, ponieważ każda aplikacja ma swoją unikalną konfigurację. Z drugiej strony powielony kod jest zawsze zły. Nie musisz zmieniać trzech miejsc, gdy wprowadzasz nową abstrakcję.

Sztuką jest przeniesienie wszystkich rejestracji w dół hierarchii projektu. Na przykład można zdefiniować pojedynczy "zespół ładowania początkowego", który zależy od zestawów warstw biznesowych (i poniżej) i pozwolić na rejestrację wszystkich tych zestawów, które się nie zmieniają.Składowe składniki aplikacji mogą następnie użyć tego zestawu, aby uzyskać domyślne rejestracje i rozszerzyć je o zależności zależne od aplikacji.

Taka sprawa może wyglądać następująco:

// MVC Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<AspNetUserContext>(); 

    DependencyResolver.Current = 
     new ContainerDependencyResolver(container); 
} 

// Windows Service Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<SystemUserContext>() 
     .SingleScoped(); 

    // Store somewhere. 
    Bootstrapper.Container = container; 
} 

// In the BL bootstrap assembly 
public static class BusinessLayerBootstrapper 
{ 
    public static void Bootstrap(Container container) 
    { 
     container.Bind<IDepenency>().To<RealThing>(); 
     // etc 
    } 
} 

Chociaż nie trzeba mieć oddzielny zespół inicjującego (można umieścić ten kod w samej BL), pozwala to zachować swoją firmę Zespoły warstwowe są wolne od wszelkich zależności od kontenera.

Zauważ, że po prostu wywołuję statyczną metodę Bootstrap(), zamiast używać (Ninject) modułów. Starałem się, aby moja odpowiedź była niezależna od ram, ponieważ twoje pytanie jest ogólne, a porady będą takie same dla wszystkich frameworków DI. Oczywiście możesz użyć funkcji modułu Ninject, jeśli chcesz.

6

chodzi scopingu aplikacja MVC musi mieć inną CompositionRoot niż usługi windows. Sugeruję, abyś spróbował jak najwięcej zorganizować za pomocą modułów funkcji (dla tych części, które są agnostyczne) oraz wszystkich innych powiązań bezpośrednio w CompositionRoot projektu MVC lub WindowsService.

Innym bardzo dobrym podejściem jest zdefiniowanie wspólnego zestawu konwencji, który pomaga wyrazić najbardziej wiążące kwestie w kilku liniach. Dlatego aplikacje mogą mieć następujące do wiązania:

MVC App

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InRequestScope())); 

Twoja usługa Windows App

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InThreadScope())); 

Z mojego punktu widzenia w połączeniu ze zorientowanych funkcji strukturyzacji podejście konwencja jest najczystszy.

Powiązane problemy