2017-02-06 34 views
5

Próbuję zmienić kod, aby użyć wtyczki zależności .NET Core w usługach mapowania w pliku startup.cs. Chciałbym wstawić tutaj IRequestDatabaseLogger zamiast go wymyślać. Wymaga to jednak kontekstu w konstruktorze. Jak mogę to osiągnąć? Czy jest to nawet możliwe bez frameworka DI, czy nawet wtedy?Wstrzykiwanie programu rejestrującego z zależnościami konstruktorów

public class ActionFilter : ActionFilterAttribute 
    { 
     public override void OnActionExecuting(ActionExecutingContext context) 
     { 
      var requestDatabaseLogger = new RequestDatabaseLogger(context); 
      long logId = requestDatabaseLogger.Log(); 

      context.HttpContext.AddCurrentLogId(logId); 

      base.OnActionExecuting(context); 
     } 
    } 
+2

Zapobiegaj wykonywaniu czynności przydatnych w atrybutach. Atrybuty powinny być pasywne, jak wyjaśniono [tutaj] (http://blog.ploeh.dk/2014/06/13/passive-attributes/) i [tutaj] (https://www.cuttingedge.it/blogs/steven /pivot/entry.php?id=98). – Steven

+0

Powiązane: https://stackoverflow.com/a/29916075/264697 – Steven

+1

Myślę, że masz na myśli * Unikaj * nie zapobiegaj (robiąc coś użytecznego) ... – ssmith

Odpowiedz

8

Jednak to wymaga kontekstu w konstruktorze.

Umożliwienie konstrukcji składników aplikacji w zależności od danych wykonawczych jest wzorcem zapobiegającym, zgodnie z opisem here. W tym artykule opisano, jak rozwiązać te problemy w ogóle.

W twoim przypadku prawdopodobnie oznacza to, że Twój komponent powinien być oparty na abstrakcji ASP.NET Core IHttpContextAccessor, co jest wzorem opisanym w cytowanym artykule.

Alternatywnie, zgodnie z opisem w artykule, można przekazać wymagane dane środowiska wykonawczego do rejestratora przy użyciu jego metody Log.

0

Wstrzykiwanie RequestDatabaseLoggerFactory w konstruktorze, którego można użyć do utworzenia instancji RequestDatabaseLogger.

public interface IRequestDatabaseLoggerFactory { 
    IRequestDatabaseLogger Create(ActionExecutingContext context); 
} 
public class RequestDatabaseLoggerFactory : IRequestDatabaseLoggerFactory { 
    public IRequestDatabaseLogger Create(ActionExecutingContext context) { 
     return new RequestDatabaseLogger(context); 
    } 
} 

public class ActionFilter : ActionFilterAttribute 
{ 
    public ActionFilter(IRequestDatabaseLoggerFactory factory) { 
     _factory = factory; 
    } 

    private readonly IRequestDatabaseLoggerFactory _factory; 

    public override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var requestDatabaseLogger = _factory.Create(context); 
     long logId = requestDatabaseLogger.Log(); 

     context.HttpContext.AddCurrentLogId(logId); 

     base.OnActionExecuting(context); 
    } 

}

+1

Odradzam używanie abstrakcji fabrycznych, jak pokazano tutaj, jak wyjaśniono [ tutaj] (https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=100). – Steven

2

Należy użyć typeFilter aby to osiągnąć, i owinąć filtr, który ma uzależnienia (w tym przypadku na rejestratorze lub kontekstu) wewnątrz filtra. Pokażę dokładny przykład tego w moim MSDN Article on ASP.NET Core Filters. Powiązany kod źródłowy to here (patrz filtr ValidateAuthorExists).

Oto, co to może wyglądać w scenariuszu:

public class MyFilterAttribute : TypeFilterAttribute 
{ 
    public MyFilterAttribute():base(typeof(MyFilterImpl)) 
    { 
    } 

    private class MyFilterImpl : IAsyncActionFilter 
    { 
     public MyFilterImpl(*inject dependencies here*) 
     {} 
    } 
} 

W ten sposób można korzystać z atrybutów w .NET Rdzenia jednocześnie wstrzykiwanie zależności pod spodem filtrem działania. Omówię to również na moim nadchodzącym kursie Core QuickStart programu ASP.NET na DevIQ.com (poszukaj go na koniec tego miesiąca).