Jak dodać globalne filtry interfejsu API sieci Web ASP.Net?

98

Utworzyłem filtr Web Api (używając System.Web.Http.Filters.ActionFilterAttribute), ale nie mogę go uruchomić wewnątrz ASP.Net MVC 4. Próbowałem dodać go do RegisterGlobalFilters()metody, ale to nie zadziałało.

Więc jeśli ktoś korzysta z interfejsu API sieci Web hostowanego w ASP.Net MVC, w jaki sposób można zarejestrować filtry?

Shane Courtrille
źródło

Odpowiedzi:

110

Poniższy kod w moim Global.asax działa dla mnie:

public static void RegisterWebApiFilters(System.Web.Http.Filters.HttpFilterCollection filters)
{
  filters.Add(new MyWebApiFilter());
}

protected void Application_Start()
{
  RegisterWebApiFilters(GlobalConfiguration.Configuration.Filters);
}
Dave Bettin
źródło
6
Czy ktoś może wyjaśnić, co się tutaj dzieje? Dlaczego istnieją dwa zestawy filtrów globalnych? Czy to nie czyni „Global” oksymoronem?
Luke Puplett
6
Jeden zestaw filtrów jest przeznaczony dla MVC, a drugi dla interfejsu API sieci Web. Są to dwie oddzielne rzeczy i zwykle nie chcesz, aby filtry jednej były stosowane do drugiej.
Shane Courtrille
2
Mój filtr WebApi jest wywoływany dwukrotnie. Czy ktoś ma ten problem?
Andrew Kalashnikov
87

Zwróć uwagę, że ta odpowiedź jest prawdą do MVC 5 / Web API 2

Krótka odpowiedź: filtry MVC i Web API nie są wzajemnie kompatybilne i jeśli chcesz zarejestrować je globalnie, musisz użyć odpowiednich klas konfiguracji dla każdego z nich.

Długa odpowiedź: ASP.NET MVC i Web API są celowo zaprojektowane do działania w podobny sposób, ale w rzeczywistości są różnymi stworzeniami.

Interfejs API sieci Web znajduje się w System.Web.Httpprzestrzeni nazw, a MVC - w System.Web.Mvcprzestrzeni nazw. Oba będą szczęśliwie żyć obok siebie, ale jeden nie zawiera drugiego i pomimo podobieństw w modelu programowania, podstawowe implementacje są różne. Tak jak kontrolery MVC i kontrolery interfejsu API sieci Web dziedziczą różne klasy kontrolerów bazowych (nazwy MVC są po prostu nazwane, Controllera nazwy interfejsów API sieci Web ApiController) Filtry MVC i filtry interfejsu API sieci Web dziedziczą z różnych FilterAttributeklas (w tym przypadku oba mają tę samą nazwę, ale są oddzielnymi klasami, które działają w odpowiednich przestrzeniach nazw).

Filtry globalne interfejsu API sieci Web są rejestrowane za pośrednictwem HttpConfigurationobiektu dostępnego w Registermetodzie WebApiConfig.cs, jeśli używasz szablonu projektu z narzędziem WebActivator:

public static void Register(HttpConfiguration config)
{
    //stuff before
    config.Filters.Add(new MyWebApiFilter());
    //stuff after
}

lub w inny sposób w global.asax.cs:

GlobalConfiguration.Configuration.Filters.Add(new MyWebApiFilter());

Filtry globalne MVC są rejestrowane za pomocą GlobalFilterCollectionobiektu, który jest dostępny za pośrednictwem RegisterGlobalFiltersmetody FilterConfig.cs dla projektów korzystających z WebActivator:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //stuff before
        filters.Add(new MyMvcFilter());
        //stuff after
    }
}

lub w pliku global.asax.cs w GlobalFilters.Filterscelu pobrania dla osób bez WebActivatora:

GlobalFilters.Filters.Add(new MyMvcFilter());

Warto zaznaczyć, że w obu przypadkach nie musisz dziedziczyć po odpowiednim FilterAttributetypie. Filtry interfejsu API sieci Web muszą implementować tylko interfejs System.Web.Http.IFilter, podczas gdy rejestracja filtru MVC sprawdza, czy klasa dziedziczy jeden z kilku interfejsów filtrów zdefiniowanych w System.Web.Mvcprzestrzeni nazw.

joelmdev
źródło
Dodanie niestandardowych filtrów Web Api w webapiconfig.cs działa dla mnie. Nie rozumiem, dlaczego to nie zadziałało po dodaniu do global.asax.cs
Tatipaka
dzięki @tatipaka. dodanie do webapiconfig zadziałało.
Gokulnath,
12

Począwszy od MVC 4 RC, poprawna nazwa klasy to HttpFilterCollection :

public static void RegisterWebApiFilters(System.Web.Http.Filters.HttpFilterCollection filters)
{
    filters.Add(new MyWebApiFilter());
}

protected void Application_Start()
{
    RegisterWebApiFilters(GlobalConfiguration.Configuration.Filters);
}
nuzzolilo
źródło
8

Zamiast używać filtrów globalnych, wolę to zrobić:

[MyWebApiFilter]
public class CustomizedApiControllerBase : ApiController
{
   ...
}

Następnie odziedzicz wszystkie kontrolery API z CustomizedApiControllerBase To podejście jest bardziej wyraziste w porównaniu z globalnymi filtrami w pliku global.ascx.

Mahmoud Moravej
źródło
Utworzyłem filtr dziedziczący po System.Web.Http.Filters.ActionFilterAttribute i zacząłem używać go bezpośrednio w metodach, których go potrzebuję. To po prostu działa, więc dlaczego nie muszę go rejestrować?
joedotnot
@joedotnot Chodzi o filtry „globalne”, a nie konkretne. Jeśli możesz określić, którą metodę chcesz filtrować, Twoje podejście jest w porządku, ale jeśli chcesz filtrować niezależnie od akcji kontrolera, potrzebujesz filtrów globalnych.
Mahmoud Moravej