2015-08-20 14 views
8

Chciałbym zastosować pewne zagadnienia przekrojowe do moich kontrolerów MVC. W tej chwili jest to realizowane przez abstrakcyjną klasę bazową, ale ponieważ refaktoryzujemy więcej kodu źródłowego, aby skorzystać z wtrysku zależności, zastanawiam się, czy to jest coś, co Simple Injector może mi pomóc dzięki swoim urządzeniom do dekoracji lub przechwytywania .Jak ozdobić kontroler ASP.NET MVC za pomocą prostego wtryskiwacza

Tak już próbowali stworzyć dość podstawowy dekorator:

public class ControllerDecorator : IController 
{ 
    private readonly IController _controller; 

    public ControllerDecorator(IController controller) 
    { 
     _controller = controller; 
    } 

    public void Execute(RequestContext requestContext) 
    { 
     // Do something of a cross-cutting nature here... 

     _controller.Execute(requestContext); 
    } 
} 

I w moim korzeni Skład: container.RegisterDecorator<IController, ControllerDecorator>()

Jednak kod w Execute sposobu mojego dekoratora nie wydają się kiedykolwiek nazywa. Czy to dlatego, że framework MVC bezpośrednio rozwiązuje moje klasy kontrolerów, zamiast przechodzić przez IController? W takim razie, co mogę zrobić? Czego tu mi brakuje?

Odpowiedz

9

W domyślnej konfiguracji nie można stosować dekoratorów do kontrolerów. Powodem tego jest to, że MVC DefaultControllerFactory żąda kontrolerów przez ich konkretny typ. Ponieważ żąda konkretnego typu, Simple Injector nie może zastosować dekoratora; musi zakładać, że osoba dzwoniąca potrzebuje tego konkretnego typu i dlatego musi zwrócić ten dokładny typ (lub podtyp).

Aby rozwiązać ten problem, trzeba będzie zastąpić domyślny DefaultControllerFactory ze zwyczajem jednym:

public class SimpleInjectorControllerFactory : DefaultControllerFactory { 
    public IDictionary<Type, InstanceProducer> Producers { get; set; } 
    protected override IController GetControllerInstance(RequestContext rc, Type type) { 
     return (IController)this.Producers[type].GetInstance(); 
    } 
} 

Następnie w inicjującego, będziesz musiał wymienić wezwanie do RegisterMvcControllers z następujących czynności:

var controllerTypes = SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
    container, Assembly.GetExecutingAssembly()); 

var controllerProducers = controllerTypes 
    .ToDictionary(type => type, type => CreateControllerProducer(container, type)); 

// Verify after creating the controller producers. 
container.Verify(); 

ControllerBuilder.Current.SetControllerFactory(
    new SimpleInjectorControllerFactory { Producers = controllerProducers }); 

Sposób CreateControllerProducer wygląda następująco:

Najważniejszą częścią jest to, że wywołanie CreateProducer jest dostarczane z typeof(IController); to pozwala Simple Injector zastosować dekorator dla IController.

To jest to; teraz możesz zarejestrować swój dekorator na IController.

Jedno ostrzeżenie: w przypadku zarówno interfejsu Web API, jak i nowego rdzenia ASP.NET niemożliwe jest zastosowanie dekoratorów do kontrolerów. Obie frakcje wymagają konkretnych rodzajów; ulegną zerwaniu, jeśli otoczysz prawdziwego kontrolera. Preferowany sposób z tymi ramami do dekorowania kontrolerów odbywa się za pośrednictwem rurociągu OWIN. Tak więc ta odpowiedź działa wyłącznie z MVC 3, 4 i 5.

+0

Niesamowite, dzięki! Musiałem jednak dokonać jednej zmiany w kodzie: w wywołaniu 'ControllerBuilder.Current.SetControllerFactory', musiałem użyć instancji' controllerFactory' utworzonej przed weryfikacją kontenera. Jeśli nie tworzysz go przed wywołaniem 'Zweryfikuj', dostanę komunikat ostrzegawczy; jeśli zostanie utworzona ponownie w metodzie 'SetControllerFactory', nic się nie dzieje i dekorator nigdy nie zostanie zastosowany. Jakiś pomysł, dlaczego tak jest? –

+0

@MartinWedvich ah tak, oczywiście. Fabryka kontrolera wyłącza diagnostykę. Obvoiusly musisz go pominąć, zanim zweryfikujesz – Steven

+0

Po wywołaniu 'container.Verify', producenci w' controllerProds' zostali zmutowani z klas kontrolerów (np. 'HomeController') na' ControllerDecorator', i wygląda na to, że jest to powód, dla którego to się nie udaje, jeśli ponownie zainstaluję fabrykę po raz drugi. Czy to zamierzone zachowanie? –

Powiązane problemy