12

Próbuję wstrzyknąć dependancy w zwyczaju AuthorizeAttribute następująco:wtryskowa nieruchomości na atrybutach

public class UserCanAccessArea : AuthorizeAttribute 
{ 
    readonly IPermissionService permissionService; 

    public UserCanAccessArea() : 
     this(DependencyResolver.Current.GetService<IPermissionService>()) { } 

    public UserCanAccessArea(IPermissionService permissionService) 
    { 
     this.permissionService = permissionService; 
    } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     string AreaID = 
      httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string; 

     bool isAuthorized = false; 

     if (base.AuthorizeCore(httpContext)) 
      isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User); 

     return isAuthorized; 
    } 
} 

To działa, ale wydaje się być rozwiązanie jako pojedyncza czyli mam problemy opisane w moim pervious question

Chciałbym użyć wtrysku właściwości, ale ponieważ mój atrybut nie został rozwiązany przez Unity, nie mogę znaleźć sposobu na skonfigurowanie kontenera do przechwytywania i rozwiązywania właściwości. Próbowałem następujące:

public class UserCanAccessArea : AuthorizeAttribute 
{ 
    public IPermissionService permissionService { get; set; } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     string AreaID = 
      httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string; 

     bool isAuthorized = false; 

     if (base.AuthorizeCore(httpContext)) 
      isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User); 

     return isAuthorized; 
    } 
} 

opakowaniu:

container.RegisterType<UserCanAccessArea>(new InjectionProperty("permissionService")); 

Ale nieruchomość jest zawsze zerowa przy starcie.

Czy ktoś to osiągnął, a jeśli tak, czy masz przykład?

Odpowiedz

27

Należy zapobiegać całkowitemu wprowadzaniu iniekcji zależności do atrybutów. Powód tego jest wyjaśniony w tym artykule: Dependency Injection in Attributes: don’t do it!. Podsumowując, w artykule wyjaśniono, że:

  • Wstrzyknięcie konstruktora nie jest możliwe, ponieważ nie można przechwycić utworzenia instancji Attribute; CLR kontroluje.
  • Użycie wstrzyknięcia właściwości jest kruche, ponieważ skutkuje to Temporal Coupling, któremu należy zapobiec.
  • Wstrzykiwanie zależności w atrybuty uniemożliwia zweryfikowanie poprawności konfiguracji kontenera .
  • Struktury takie jak atrybuty pamięci podręcznej MVC i Web API, dzięki czemu bardzo łatwo przypadkowo utworzyć captive dependencies powodując błędy.

Masz dwie możliwości tutaj:

  1. podjęciu atrybuty pasywny, poprzez podział danych (atrybutu) z jego zachowania (usługi) Jak wyjaśniono w referenced article i this related article Mark Seemann.
  2. Zmień swoje atrybuty na humble objects zgodnie z wyjaśnieniem w this answer. Oznacza to:
    1. wyodrębnić całą logikę z atrybutu do niestandardowej usługi, która zawiera wszystkie zależności.
    2. Zarejestruj tę usługę w swoim kontenerze.
    3. pozwól, aby metoda atrybutu (AuthorizeCore w twoim przypadku) nie robiła nic więcej niż rozwiązywanie usługi z lokalizatora usług/DependencyResolver i wywoływanie metody usługi. Należy zauważyć, że nie można wykonywać iniekcji konstruktora, wtrysku własności, a usługa nie może być przechowywana w stanie prywatnym (jak już zauważyliśmy).

Która opcja użycia:

  • Użyj opcji 1, jeśli są bardzo chętni do utrzymywania projektowania czyste, czy masz więcej niż kilka cech, które należy stosować w ten sposób, lub chcesz zastosować atrybuty są zdefiniowane w zespole, który nie zależy od System.Web.Mvc.
  • Użyj opcji 2 w przeciwnym razie.
+0

Odkryłem opcję 1 i wydaje się, że nie można jej użyć, jeśli określono, że element dbcontext ma zostać rozstrzygnięty InRequestScope (Ninject). W przeciwnym razie działa idealnie. Próbowałem go najpierw z lokalizatorem usług (anti-pattern, ale rozwiązuje tworzenie obiektów usługowych). Problem z niestandardowym atrybutem autoryzowanym polega na tym, że został utworzony w czasie wykonywania i nie jest zgodny z InRequestScope. Proszę, popraw mnie jeśli się mylę. –

+0

Chcę użyć opcji InRequestScope, ponieważ chcę mieć jeden i ten sam dbcontext podczas pracy z różnymi repozytoriami i móc korzystać z UnitOfWork - jedno miejsce do wywoływania zapisów w dbcontext. –

+0

Jedną z idei nie jest użycie DI dla usługi, ale wystarczy utworzyć rzeczywisty obiekt używany w filtrze Autoryzacja. Czy to dobre podejście? To sprawi, że mój kod będzie brzydki, ponieważ usługa, którą chcę, ma inne usługi zależne i repozytoriom .... –

Powiązane problemy