paint-brush
ASP.NET Core'da Autofac ContainerBuilder İçin Bilmeniz Gereken İpuçlarıile@devleader
313 okumalar
313 okumalar

ASP.NET Core'da Autofac ContainerBuilder İçin Bilmeniz Gereken İpuçları

ile Dev Leader12m2024/05/10
Read on Terminal Reader

Çok uzun; Okumak

Bağımlılık eklemeyi bağlamak için ASP.NET Core'da Autofac ContainerBuilder'ı nasıl kullanacağınızı öğrenin. Bu yaklaşımla neler yapabileceğimizi ve yapamayacağımızı keşfedeceğim!
featured image - ASP.NET Core'da Autofac ContainerBuilder İçin Bilmeniz Gereken İpuçları
Dev Leader HackerNoon profile picture
0-item


Uygulamalarımızda bağımlılık enjeksiyonunu yönetmenin birçok yolu vardır ve farklı yaklaşımların faydalarını ve sınırlamalarını anlamanın önemli olduğunu düşünüyorum. Bağımlılıklarınızı yapılandırmanın birincil yolu olarak önerilen AutofacServiceProviderFactory yerine ASP.NET Core'da bir Autofac ContainerBuilder kullanmak keşfedebileceğimiz yollardan biridir!


Bu makalede ASP.NET Core uygulamanızda AutofacServiceProviderFactory yerine Autofac's ContainerBuilder'ı nasıl kullanacağınızı vurguluyorum. Bağımlılık enjeksiyonuyla erişebildiğimiz diğer yaklaşımlara kıyasla bu yaklaşımla neler yapabileceğinize ve yapamayacağınıza bakacağız.


Bu, ASP.NET Core içindeki Autofac ile bağımlılık çözümlemesini araştıracağım bir serinin parçası olacak. Sayılar yayınlandıkça aşağıdaki seriye de yer vereceğim:


Bu serinin sonunda ASP.NET Core ve Blazor içindeki eklenti mimarilerini daha güvenli bir şekilde keşfedebileceksiniz ve bu, keşfetmeniz için daha da fazla içerik sağlayacak.


AutofacServiceProviderFactory ile İlgili Sorun

Adil olmak gerekirse, bölüm başlığı *neredeyse* tıklama tuzağıdır. ASP.NET Core uygulamalarınızda Autofac'ı kurmanın önerilen yolu olarak AutofacServiceProviderFactory kullanılmasının çoğu uygulama için harika olduğunu düşünüyorum. Autofac'ı bağımlılık enjeksiyon çerçevesi olarak kullanmak isteyen geliştiricilerin büyük çoğunluğu bu şekilde pek fazla sorunla karşılaşmayacaktır.


Bize aşağıdakileri yapma olanağı sağlar:

  • WebApplicationBuilder (ve şu anda mevcut olan her şeye) erişin
  • IConfiguration örneğine erişim ( WebApplicationBuilder örneğinde de mevcuttur)
  • Bağımlılıkları minimum API'lere aktarabilme yeteneği


Ancak benim için büyük sorun: WebApplication örneğine erişemiyoruz. C#'ta eklenti mimarileri oluşturduğumda, özellikle ASP.NET Core uygulamaları oluştururken, rotaları kaydetmek için WebApplication örneğine erişime sahip olmayı seviyorum. Bu, eklentilerimden minimum sayıda API'yi kolaylıkla kaydetmeme olanak tanıyor; kullanışlı sözdizimini elde etmek için teknik olarak yalnızca IEndpointRouteBuilder uygulamasına erişim gerekiyor.

Minimal olmayan API'leri bu olmadan kaydedebilir miyim? Kesinlikle. Benzer bir sözdizimi sağlamanın ve WebApplication örneğini gerektirmenin başka bir yolu var mı? Büyük ihtimalle. Ancak BU soruna geçici bir çözüm bulmaya çalışmak yerine, ilgilendiğim bağımlılığa erişip erişemeyeceğimi görmek istedim.


Bağımlılık kapsayıcımı nasıl kuracağıma dair planı değiştirmenin zamanı gelmişti!


Örnek Bir ASP.NET Çekirdek Uygulamasını Keşfetme

Keşfedecek bazı ortak noktalara sahip olmak için örnek bir uygulamaya bakalım. Önceki makaleyi okuduysanız, bu da benzer görünecektir; örnek hava durumu uygulamasının bir varyasyonu:

 using Autofac; using Microsoft.AspNetCore.Mvc; // personal opinion: // I absolutely love having the entry point of my // applications being essentially: // - make my dependencies // - give me the primary dependency // - use it // - ... nothing else :) ContainerBuilder containerBuilder = new(); containerBuilder.RegisterModule<MyModule>(); using var container = containerBuilder.Build(); using var scope = container.BeginLifetimeScope(); var app = scope.Resolve<WebApplication>(); app.Run(); internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } internal sealed class MyModule : Module { protected override void Load(ContainerBuilder containerBuilder) { containerBuilder.RegisterType<DependencyA>().SingleInstance(); containerBuilder.RegisterType<DependencyB>().SingleInstance(); containerBuilder.RegisterType<DependencyC>().SingleInstance(); containerBuilder .Register(ctx => { var builder = WebApplication.CreateBuilder(Environment.GetCommandLineArgs()); return builder; }) .SingleInstance(); containerBuilder .Register(ctx => ctx.Resolve<WebApplicationBuilder>().Configuration) .As<IConfiguration>() .SingleInstance(); containerBuilder .Register(ctx => { var builder = ctx.Resolve<WebApplicationBuilder>(); var app = builder.Build(); app.UseHttpsRedirection(); // FIXME: the problem is that the Autofac ContainerBuilder // was used to put all of these pieces together, // but we never told the web stack to use Autofac as the // service provider. // this means that the minimal API will never be able to // find services off the container. we would need to resolve // them BEFORE the API is called, like in this registration // method itself, from the context that is passed in. //DependencyA dependencyA = ctx.Resolve<DependencyA>(); // FIXME: But... What happens if something wants to take a // dependency on the WebApplication instance itself? Once the // web application has been built, there's no more adding // dependencies to it! var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; app.MapGet( "/weatherforecast", ( [FromServices] DependencyA dependencyA , [FromServices] DependencyB dependencyB , [FromServices] DependencyC dependencyC ) => { var forecast = Enumerable .Range(1, 5) .Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }); return app; }) .SingleInstance(); } } internal sealed class DependencyA( WebApplicationBuilder _webApplicationBuilder); internal sealed class DependencyB( WebApplication _webApplication); internal sealed class DependencyC( IConfiguration _configuration);


Bu yaklaşımın vurguladığı noktalardan biri, Autofac ContainerBuilder sınıfını birincil bağımlılık konteynerimiz olarak kullanmanın bize giriş noktamızı şu şekilde yapılandırma fırsatını vermesidir:

  • Kapsayıcı oluşturma
  • Bağımlılık kaydı
  • Birincil bağımlılık çözümü
  • … Uygulamayı başlatmak için tek bir yöntemi çağırın!


Bana göre bu ideal uygulama başlatma kodudur. Neden? Çünkü ona dokunmak için asla buraya gelmene gerek yok. Durmadan. İçine ne kadar şey eklerseniz ekleyin! Ve hepsi bu, çünkü daha fazla modül yüklemek için montajları tarayabilirsiniz.

Tekrar söylüyorum bu benim kişisel tercihimdir ve herkesin hedefinin bu olması gerektiğini iddia etmeye çalışmıyorum.

ASP.NET Core'da Autofac ContainerBuilder'ın Kusurları

Elbette kurşun geçirmez olmayan başka bir yaklaşım. O halde Autofac'ın bu kurulumunda neyi elde edemediğimizi tartışalım:

  • Minimal API'lerde iletilen hizmet tarafından çözümlenen parametreler kesinlikle çalışmaz. Oluşturulan WebApplication , Autofac'ı bağımlılık enjeksiyon çerçevesi olarak kullanacak şekilde yapılandırılmadı!
  • Önceki makalede olduğu gibi, WebApplication örneğini hala bağımlılık kapsayıcısına alamıyoruz… Bu nedenle, özellikle buna erişme konusunda herhangi bir ilerleme kaydetmedik.


Ama çoğunlukla bu kadar! Bu çok kötü bir dezavantaj listesi değil, ancak Autofac ContainerBuilder yaklaşımı bizim için sihirli bir çözüm değildi. Peki bundan ne çıkardık? aynı zamanda aşağıdakilerin açıklanmasına da yardımcı olacaktır:

ASP.NET Core'da Autofac ContainerBuilder'ın Avantajları

Yaptığımız her şeyin artıları ve eksileri! Artık ASP.NET Core'da Autofac ContainerBuilder ile ilgili sorunları gördüğümüze göre, bundan ne gibi ilerlemeler elde ettiğimize bakmanın zamanı geldi:


  • WebApplicationBuilder ve IConfiguration örneklerine hâlâ erişebiliyoruz; dolayısıyla bu, AutofacServiceProviderFactory yaklaşımını kullanmanın karşılaştırılabilir bir avantajıdır.
  • Programımıza oldukça akıcı bir giriş noktası elde edebiliriz ki bunu gerçekten görmek isterim. Konteyner oluşturma, kayıt etme, giriş noktası yönteminizi çözümleme, hepsi bu!
  • Minimal API'ler çalışır ancak bağımlılıklarla çalışmaz. Yine de minimum API'lerin istediği bağımlılıkları önceden çözebilir ve bunları yöntem kaydı sırasında iletebiliriz. Yorumlanan kodu görün!

Eklenti Tabanlı ASP.NET Rotaları için Daha Fazla Ters Çevirme mi istiyorsunuz?

Bir Autofac kayıt yöntemi içerisinde minimal API'leri kaydedebildiğimizi gördük, ancak ne yazık ki konteynerden gelen bağımlılıkları doğrudan minimal API çağrısının kendisinde çözemiyoruz. Bağımlılıkların otomatik olarak çözülmesiyle rota tanımlarını işleyen aşağıdaki gibi özel bir sınıf oluşturabiliriz:

 internal sealed class WeatherForecastRoutes( DependencyA _dependencyA // FIXME: still can't depend on this because // we can't get the WebApplication //, DependencyB _dependencyB , DependencyC _dependencyC) { private static readonly string[] _summaries = new[] { "Freezing", "Bracing", // ... }; public WeatherForecast[] Forecast() { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), _summaries[Random.Shared.Next(_summaries.Length)] )) .ToArray(); return forecast; } }


Bu sınıfa VE bağımlılıkların tümü aynı kaptaysa, otomatik çözümleme gerçekleşir. O zaman bu kodu çağırmanız yeterli:

 var weatherForecastRoutes = ctx.Resolve<WeatherForecastRoutes>(); app.MapGet("/weatherforecast2", weatherForecastRoutes.Forecast);


Eklenti açısından bakıldığında bu hala biraz berbat çünkü kayıt kodunu bu şekilde çağırmak için tüm rota sınıflarını manuel olarak çözmemiz gerekecek - bunların hepsi bu şeylerin WebApplication kendi erişimlerini çözememeleri gerçeğinden kaynaklanıyor misal.


Ama durun… Peki ya işleri tersine çevirirsek? Ya IRegisterRoutes gibi bir arayüzü çözüp WebApplication örneğine aktarabilseydik?!

 // NOTE: make sure to register WeatherForecastRouteRegistrar on the // autofac container as IRegisterRoutes! internal interface IRegisterRoutes { void RegisterRoutes(WebApplication app); } internal sealed class WeatherForecastRouteRegistrar( WeatherForecastRoutes _weatherForecastRoutes) : IRegisterRoutes { public void RegisterRoutes(WebApplication app) { app.MapGet("/weatherforecast2", _weatherForecastRoutes.Forecast); } } // TODO: add this to the autofac code where the // WebApplication instance is built: foreach (var registrar in ctx.Resolve<IEnumerable<IRegisterRoutes>>()) { registrar.RegisterRoutes(app); }


Artık WebApplication örneğinin eklentilerimiz tarafından erişilebilir olup olmadığını umursamamıza bile gerek yok! Belki de ilk versiyon o kadar sınırlayıcı değildi. Belki burada bir şeyin peşindeyizdir… Ancak bir sonraki makale bunu daha ayrıntılı olarak açıklamalıdır.


ASP.NET Core'da Autofac ContainerBuilder'ı Sarma

Bu makalede, normalde önerildiği gibi AutofacServiceProviderFactory kullanmak yerine açıkça bir Autofac ContainerBuilder kullanmayı araştırdım. Bazı benzer fayda ve dezavantajların yanı sıra dikkate alınması gereken farklı hususları da gördük. Her yol, başvurunuzda neyin peşinde olduğunuza bağlı olarak artılar ve eksiler sunabilir.


İlginç olan şu ki, eğer eklentiler üzerinde çalışmaya çalışıyorsak, eklentilerimizden WebApplication örneğine erişmemize bile gerek kalmayabilir! Minimal API'leri önemsiyorsak, bu yine de sınırlayıcı olabilir… ancak aksi halde ilginç bir düşünce tarzına sahibiz!

Bunu yararlı bulduysanız ve daha fazla öğrenme fırsatı arıyorsanız, haftalık ücretsiz yazılım mühendisliği bültenime abone olmayı ve YouTube'daki ücretsiz videolarıma göz atmayı düşünün!