konfiguracja

Web Api z .NET 4.5.2 + CORS + Autofac

Skoro już zaprzyjaźniłem się z Aurelią to warto byłoby stworzyć WebApi do mojej aplikacji, które to aplikacja stworzona za pomocą wyżej wspomnianej Aurelii będzie z radością konsumować. Wybrałem podejście WebApi, bo:

  1. WebApi2, czyli .Net Core nie chciał działa z Autofac’iem. Próbowałem podpiąć Autofac po zainstalowaniu Update 3 dla Visual Studio 2015 i niestety dostawałem błąd z klasy Microsoft.Extensions.DependencyInjection. Wyjątek, a i owszem zapisałem, ale tak dobrze, że nie mogę go znaleźć. Jeżeli uda mi się go jeszcze raz wywołać to uzupełnię to miejsce.
  2. NancyFX, a i owszem chciałem, ale okazało się, że nie ma szablonu dla VS 2015. Nie to nie, chociaż można oczywiście użyć Nancy bez szablonu.

A więc pozostało mi stare WebApi i pomyślałem  „dlaczego nie?”. W sumie w nim też nigdy nic nie napisałem.

Do dzieła. Wybrałem projekt „ASP.NET Web Application (.NET Framework)”, a następnie zaznaczyłem „Empty”, a potem wybrałem „WebApi”. Mam to. Kolejna sprawa to CORS, bo jest duże prawdopodobieństwo, że frontendowa część aplikacji będzie pochodzić z innej domeny czy też będzie dostępna na innym porcie niż część serwerowa. A właściwie to już tak jest, bo development też wymusza użycie różnych portów.

Cross-Origin Resource Sharing to, jak mówi sama Wikipedia, mechanizm umożliwiający współdzielenie zasobów pomiędzy serwerami znajdującymi się w różnych domenach. Ściślej rzecz biorąc chodzi o możliwość wykonywania żądań AJAX między takimi serwerami przy zachowaniu pewnych ograniczeń co do dopuszczalnego źródła żądania.

Aby umożliwić CORS wystarczy dodać do projektu referencję System.Web.Http.Cors z nugetowego pakietu Microsoft.AspNet.WebApi.Cors, następnie w klasie WebApiConfig.cs (metoda Register) wstawić następujący kawałek kodu:

var cors = new EnableCorsAttribute("http://localhost:9000", "*", "*");
config.EnableCors(cors);

Działa, chociaż nie od razu działało. Zupełnie przypadkiem zacząłem całą drogę naokoło. Najpierw oprócz powyższego wpisu dodawałem jeszcze różnej maści wpisy w web.configu:

Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
Access-Control-Allow-Origin: *

Następnie dekorowałem atrybutem EnableCors każdy kontroler mojego Api. Nie. Wystarczy po prostu to co jest powyżej.

I jeszcze jedno. Gdyby ktoś dostał błąd:

Fetch API cannot load http://localhost:49911/api/ohdev. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 500. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

to może spróbować od usunięcia ostatniego slasha z adresu podanego jako parametr konstruktora EnableCorsAttribute – oczywiście jeżeli ten slash tam się znajduje.

http://localhost:9000 - dobrze
http://localhost:9000/ - źle

OK, czas na Autofac, czyli kontener, który wstrzyknie wszystko tam gdzie trzeba i nie będziemy musieli się martwić o zależności. Dlaczego Autofac? Bo koledzy go używają, a ja ich bardzo cenię i nie zamierzam się mądrzyć.

Zaczynam od dwóch nugetowych paczek Autofac i Autofac.WebApi oraz wstawienia kodu prosto z dokumentacji Autofac:

protected void Application_Start()
{
  var builder = new ContainerBuilder();
  var config = GlobalConfiguration.Configuration;
  builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
  var container = builder.Build();
  config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
  GlobalConfiguration.Configure(WebApiConfig.Register);
}

i dostaję w twarz pięknym błędem:

Nie można załadować pliku lub zestawu 'Autofac' lub jednej z jego zależności.

Okazało się, że najlepiej zainstalować tylko jedną paczkę: Autofac.WebApi, a podczas instalacji zostanie już doinstalowany Autofac we właściwej wersji. Ja miałem rozbieżności i dostawałem błąd.

Jedziemy dalej. Kolejne F5 i:

Naruszono reguły zabezpieczeń dziedziczenia podczas zastępowania elementu członkowskiego: Autofac.Integration.WebApi.AutofacWebApiDependencyResolver.BeginScope(). Dostępność zabezpieczeń metody zastępującej musi być taka sama jak dostępność zabezpieczeń metody zastępowanej.

W końcu doczytałem na jednym z wpisów na StackOverflow, że dla ostatnich klasycznych WebApi należy stosować Autofac.WebApi2. Nie doczytałem, a szczerze powiedziawszy to nadal nie mam pewności czy to jest tam napisane. Teraz to jest nieważne. Po dwóch wieczorach nierównej walki … BANGLA.

Jeszcze tylko rejestracja jednej klasy z jednym parametrem w konstruktorze:

builder.RegisterType<DbFactory>().As<IDbFactory>().WithParameter("connectionString", ConfigurationManager.ConnectionStrings["ohdevConnectionString"].ConnectionString);

Do tego rejestracja generycznego repozytorium:

builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));

A na koniec rejestracja wszystkich typów w projekcie, w którym znajduje się klasa OhDev:

var domainAssembly = typeof (OhDev).Assembly;
builder.RegisterAssemblyModules(domainAssembly);

Działa!!!

Leave a Reply

Your email address will not be published. Required fields are marked *