Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

Dependency Injection in ASP.NET Core with .NET 6

ASP.NET Core'da .NET 6'da Dependency Injection, bir bileşenin (servis veya nesne) ihtiyaç duyduğu diğer bileşenlerin dışarıdan sağlanması anlamına gelir. Bu, kodun daha temiz, esnek ve bakımı daha kolay hale gelmesini sağlar. Bağımlılıklar genellikle bir bağımlılık enjeksiyon konteyneri tarafından yönetilir ve bu konteyner, gerekli nesneleri otomatik olarak oluşturur veya ayarlar. Bu sayede yazılım geliştirme süreci daha verimli hale gelir.

What is dependency injection?

Dependency Injection (DI) bir yazılım tasarım desenidir ve bir yazılım bileşeni, nesne veya servis tarafından başka bir bileşene ihtiyaç duyulduğunda, bu bağımlılığı dışarıdan, genellikle bir container aracılığıyla, enjekte etmeyi sağlar. ASP.NET Core gibi modern web uygulama çatıları, Dependency Injection’i standart bir bileşen olarak sunar. .NET 6’da, Dependency Injection oldukça güçlü bir şekilde entegre edilmiştir.

Dependency Injection’in temel amacı, yazılım bileşenlerinin birbirine bağımlılıklarını azaltmak ve kodun daha esnek, test edilebilir ve bakımı kolay hale getirmektir. Bağımlılıkların kod içine sıkıştırılması yerine, DI ile bu bağımlılıkların dışarıdan enjekte edilmesi sağlanır.

Dependency Injection’in önemli bileşenleri:

  1. Servisler (Services): Bir uygulama içindeki iş mantığını yürüten ve çeşitli görevleri gerçekleştiren bileşenlerdir. Örneğin, bir veritabanı işlemi gerçekleştiren bir servis veya dış API ile etkileşimde bulunan bir servis olabilir.
  2. Bileşenler (Components): Bir uygulamanın yapı taşlarıdır ve birbirleriyle etkileşim içinde olurlar. Controller’lar, Middleware’ler, View’lar ve diğer bileşenler buna örnektir.
  3. Container: Servislerin ve bileşenlerin yönetildiği yerdir. Bu, servislerin oluşturulduğu, konfigüre edildiği ve enjekte edildiği bir mekanizmadır.

ASP.NET Core’da Dependency Injection kullanımı oldukça kolaydır. İlk olarak, uygulama yapılandırıldığında veya başlatıldığında, bir DI Container oluşturulur ve gerekli servisler bu container’a eklenir. Sonra, bileşenlerin ihtiyaç duyduğu servisler, bileşenin kurucusuna veya özelliklerine enjekte edilir.

Kod örneği ile anlatmak gerekirse:

// Örnek bir servis arayüzü
public interface IMyService
{
    void PerformAction();
}

// Örnek bir servis uygulaması
public class MyService : IMyService
{
    public void PerformAction()
    {
        Console.WriteLine("MyService is performing an action.");
    }
}

// Bileşenimiz
public class MyComponent
{
    private readonly IMyService _myService;

    // Constructor Injection ile servis enjeksiyonu
    public MyComponent(IMyService myService)
    {
        _myService = myService;
    }

    public void MyMethod()
    {
        // Servis üzerinde işlem yapabiliriz
        _myService.PerformAction();
    }
}

// Program.cs
class Program
{
    static void Main(string[] args)
    {
        // Servislerin ve bileşenlerin kaydedildiği DI Container oluşturulur
        var services = new ServiceCollection();

        // Servisimizi ekleyelim
        services.AddSingleton<IMyService, MyService>();

        // Bileşenimizi ekleyelim
        services.AddTransient<MyComponent>();

        // DI Container oluştur
        var serviceProvider = services.BuildServiceProvider();

        // Bileşeni çöz ve kullan
        var myComponent = serviceProvider.GetRequiredService<MyComponent>();
        myComponent.MyMethod();
    }
}

Yukarıdaki örnekte, MyComponent sınıfı, IMyService arayüzünü kullanarak bir servise bağımlıdır. MyComponent sınıfının kurucusu aracılığıyla bu servis enjekte edilir. Program başlatıldığında, DI Container oluşturulur ve gerekli servisler bu container’a eklenir. Sonra, MyComponent bileşeni DI Container’dan çözülür ve kullanılmaya hazır hale gelir.

Dependency Injection, yazılım bileşenlerinin esnek, test edilebilir ve bakımı kolay olmasını sağlar ve genellikle büyük ölçüde kod tekrarını azaltır ve koddaki bağımlılıkları azaltır. Bu da daha modüler, yeniden kullanılabilir ve genel olarak daha sağlıklı bir kod tabanı oluşturmanıza olanak tanır.

Service lifetimes

Dependency Injection (DI) ile birlikte, servislerin yaşam döngüsü veya ömrü (service lifetimes) oldukça önemlidir. Servislerin ömrü, bir DI Container tarafından yönetilir ve bu, bir servisin ne kadar süreyle saklanacağını, ne zaman oluşturulacağını ve ne zaman atılacağını belirler. .NET 6’da ASP.NET Core, farklı hizmet ömürlerini yönetmek için üç farklı liftime sağlar: Transient, Scoped ve Singleton.

  1. Transient Lifetimes: Transient lifetime’a sahip bir servis her seferinde istendiğinde yeni bir örnek oluşturulur. Bu, her talep geldiğinde yeni bir nesne oluşturularak hafıza tüketimini artırabilir, ancak genellikle hafif veya durum içermeyen servisler için idealdir.
  2. Scoped Lifetimes: Scoped lifetime’a sahip bir servis, bir HTTP isteği süresince veya bir iş parçacığı tarafından işlenen bir işlem süresince aynı örneği kullanır. Bu, bir HTTP isteği boyunca aynı nesnenin paylaşılmasını sağlar. Genellikle, bir HTTP isteği sırasında aynı nesneye erişim gerektiğinde kullanılır.
  3. Singleton Lifetimes: Singleton lifetime’a sahip bir servis, uygulama yaşam döngüsü boyunca tek bir örneğe sahiptir. Bu, uygulama genelinde paylaşılan nesneler veya sık kullanılan ve değişmeyen nesneler için idealdir.

Kod örnekleriyle açıklamak gerekirse:

// Örnek bir servis arayüzü
public interface IMyService
{
    void PerformAction();
}

// Örnek bir servis uygulaması
public class MyService : IMyService
{
    public MyService()
    {
        Console.WriteLine("MyService instance created.");
    }

    public void PerformAction()
    {
        Console.WriteLine("MyService is performing an action.");
    }
}

// Program.cs
class Program
{
    static void Main(string[] args)
    {
        var services = new ServiceCollection();

        // Transient lifetime örneği
        services.AddTransient<IMyService, MyService>();

        // Scoped lifetime örneği
        services.AddScoped<IMyService, MyService>();

        // Singleton lifetime örneği
        services.AddSingleton<IMyService, MyService>();

        var serviceProvider = services.BuildServiceProvider();

        // Transient lifetime örneği al
        var transientInstance1 = serviceProvider.GetRequiredService<IMyService>();
        transientInstance1.PerformAction();

        var transientInstance2 = serviceProvider.GetRequiredService<IMyService>();
        transientInstance2.PerformAction();

        // Scoped lifetime örneği al
        using (var scope = serviceProvider.CreateScope())
        {
            var scopedInstance1 = scope.ServiceProvider.GetRequiredService<IMyService>();
            scopedInstance1.PerformAction();

            var scopedInstance2 = scope.ServiceProvider.GetRequiredService<IMyService>();
            scopedInstance2.PerformAction();
        }

        // Singleton lifetime örneği al
        var singletonInstance1 = serviceProvider.GetRequiredService<IMyService>();
        singletonInstance1.PerformAction();

        var singletonInstance2 = serviceProvider.GetRequiredService<IMyService>();
        singletonInstance2.PerformAction();
    }
}

Yukarıdaki kod örneğinde, MyService sınıfı, IMyService arayüzünü uygular ve her bir servis ömrü için ayrı ayrı kaydedilir. Main metodu içinde, önce Transient lifetime, sonra Scoped lifetime ve en son Singleton lifetime örnekleri alınır ve bu örneklerin davranışları gözlemlenir.

Dependency Injection’in bu servis ömrü kontrolleri, uygulama davranışını daha iyi kontrol etmenize, hafıza kullanımını optimize etmenize ve gereksinimlere göre servislerin ömürlerini ayarlayarak performansı artırmanıza olanak tanır.

Configuring Dependency Injection in ASP.NET Core

Setting up the services

ASP.NET Core’da Dependency Injection (DI) kullanarak hizmetleri yapılandırmak, uygulamanın ihtiyaç duyduğu servisleri tanımlamak ve sağlamak için önemlidir. Uygulama başlatıldığında, ASP.NET Core runtime, servisleri yapılandırmak ve DI Container’a kaydetmek için bir Startup sınıfını kullanır. Bu sınıf, ConfigureServices yöntemi aracılığıyla servislerin kaydedilmesini ve DI Container’a eklenmesini sağlar.

Aşağıda, bir ASP.NET Core uygulamasında servislerin nasıl yapılandırılacağını adım adım açıklayan bir örnek verilmiştir:

  1. Startup Sınıfının Oluşturulması: İlk olarak, bir Startup sınıfı oluşturulur. Bu sınıf, uygulamanın başlatılması ve yapılandırılması için gerekli olan ayarları sağlar.
  2. ConfigureServices Metodunun Oluşturulması: Startup sınıfında, ConfigureServices metodunu oluşturun. Bu metod, uygulamanın hizmetlerini yapılandırmak için kullanılır.
  3. Servislerin Eklenmesi: ConfigureServices metodunda, uygulamanın ihtiyaç duyduğu servisler eklenir. Bu, IServiceCollection arayüzü üzerinden yapılır.
  4. DI Container’a Servislerin Kaydedilmesi: Eklenen servisler, DI Container’a kaydedilir ve bu sayede uygulama genelinde kullanılabilir hale gelir.

Örnek bir ASP.NET Core uygulamasında servislerin nasıl yapılandırılacağını gösteren bir kod örneği:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class Startup
{
    // ConfigureServices metodu, servisleri yapılandırmak için kullanılır
    public void ConfigureServices(IServiceCollection services)
    {
        // Örnek bir servisin eklenmesi
        services.AddTransient<IMyService, MyService>();

        // Başka bir servisin eklenmesi
        services.AddScoped<IAnotherService, AnotherService>();

        // Singleton bir servisin eklenmesi
        services.AddSingleton<ISingletonService, SingletonService>();
    }

    // Configure metodu, HTTP isteği işleyicisi (middleware) ve diğer bileşenlerin yapılandırılması için kullanılır
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        });
    }
}

// Örnek bir servis arayüzü
public interface IMyService
{
    void PerformAction();
}

// Örnek bir servis uygulaması
public class MyService : IMyService
{
    public void PerformAction()
    {
        // Servisin gerçekleştirdiği bir işlem
    }
}

// Başka bir servis arayüzü
public interface IAnotherService
{
    void DoSomething();
}

// Başka bir servis uygulaması
public class AnotherService : IAnotherService
{
    public void DoSomething()
    {
        // Başka bir servisin gerçekleştirdiği bir işlem
    }
}

// Singleton bir servis arayüzü
public interface ISingletonService
{
    void DoSomething();
}

// Singleton bir servis uygulaması
public class SingletonService : ISingletonService
{
    public void DoSomething()
    {
        // Singleton bir servisin gerçekleştirdiği bir işlem
    }
}

Yukarıdaki örnekte, Startup sınıfı içinde ConfigureServices metodu aracılığıyla servisler eklenmiştir. services.AddTransient, services.AddScoped ve services.AddSingleton metotlarıyla sırasıyla Transient, Scoped ve Singleton servisler eklenmiştir. Bu metotlar, IServiceCollection nesnesini döndürerek servislerin DI Container’a kaydedilmesini sağlar.

Bu yapılandırma, ASP.NET Core uygulamanızın servis ihtiyaçlarını tanımlamanıza ve yönetmenize olanak sağlar. Dependency Injection, kodunuzu daha modüler hale getirir ve test edilebilirliği artırırken, DI Container sayesinde bu servislerin kullanılabilirliğini ve yaşam döngülerini yönetmenizi sağlar.

How to configure dependency injection

ASP.NET Core, .NET 6’da da kullanılan güçlü bir web framework’üdür ve bağımlılık enjeksiyonu (Dependency Injection – DI) için zengin bir destek sunar. Bu özellik, bileşenler arasındaki bağımlılıkları yönetmeyi ve kodunuzun daha test edilebilir, esnek ve bakımı daha kolay hale gelmesini sağlar.

Başlamadan önce, bir ASP.NET Core projesinde dependency injection’ı yapılandırmak için iki önemli kavramı anlamak önemlidir:

  1. Servisler (Services): Servisler, uygulamanızın farklı bileşenlerinin (örneğin, veritabanı erişimi, dosya işlemleri, dış API çağrıları vb.) işlevselliğini sağlayan nesnelerdir.
  2. Servis Bağlamı (Service Container): Servis bağlamı, bir ASP.NET Core uygulamasında servislerin kaydedildiği ve çözümlendiği yerdir.

Şimdi, dependency injection’ı yapılandırmak için adımlara bir göz atalım:

Adım 1: Servislerin Kaydedilmesi

ASP.NET Core’da, ConfigureServices() yöntemi, servislerin kaydedildiği ve yapılandırıldığı yerdir. Bu yöntem, IServiceCollection arabirimi üzerinden erişilen bir yapıya sahiptir. Örneğin:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<ISomeService, SomeServiceImplementation>();
    services.AddScoped<IOtherService, OtherServiceImplementation>();
    services.AddSingleton<ISingletonService, SingletonServiceImplementation>();
}

Yukarıdaki örnek, farklı servis türlerini (Transient, Scoped, Singleton) kaydeder. Bunlar arasındaki temel fark, servislerin yaşam döngüsüdür:

  • Transient: Her talep edildiğinde yeni bir örnek oluşturulur.
  • Scoped: Her HTTP isteği için bir örnek oluşturulur.
  • Singleton: Uygulama boyunca tek bir örnek oluşturulur.
Adım 2: Servis Bağlamının Oluşturulması

Servislerin kaydedilmesinden sonra, ConfigureServices() yöntemi çağrıldığında, bir IServiceProvider örneği oluşturulur. Bu, uygulamanın diğer bileşenlerinin bu servislere erişimini sağlar.

Adım 3: Servislerin Kullanımı

Servisleri kullanmak için, bunları bir bileşenin (controller, servis, middleware, vb.) yapıcı işlevine enjekte etmek yeterlidir. ASP.NET Core, yapılandırılan dependency injection sayesinde bu enjeksiyonu otomatik olarak sağlar.

public class SomeController : ControllerBase
{
    private readonly ISomeService _someService;

    public SomeController(ISomeService someService)
    {
        _someService = someService;
    }

    public IActionResult SomeAction()
    {
        // _someService'i kullanarak işlemler yapın
        return Ok();
    }
}

Yukarıdaki kod, SomeController sınıfına ISomeService türündeki bir servisin enjekte edilmesini sağlar. Bu, SomeController sınıfının _someService özelliğini kullanarak bu servise erişebileceği anlamına gelir.

Dependency injection, kodunuzu daha test edilebilir, esnek ve bakımı daha kolay hale getiren güçlü bir desendir. ASP.NET Core, dependency injection’ı yapılandırmak için sağlam bir altyapı sunar ve yukarıdaki adımları takip ederek bunu başarılı bir şekilde kullanabilirsiniz.

Other dependency injection configuration methods

ASP.NET Core’da, dependency injection (bağımlılık enjeksiyonu) yapılandırması için ConfigureServices yöntemi en yaygın kullanılan yöntemdir. Ancak, bazı durumlarda farklı yapılandırma yöntemlerini kullanmak isteyebilirsiniz. Bu yöntemler, özellikle büyük ve karmaşık projelerde daha fazla esneklik sağlayabilir.

1. Servis Sağlayıcı Kullanma (Using Service Provider)

ASP.NET Core’da, Configure yöntemi aracılığıyla doğrudan bir IServiceProvider kullanarak servisleri yapılandırabilirsiniz. Bu yöntem genellikle middleware bileşenlerinde veya startup sınıfının Configure yönteminde kullanılır.

public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
    // Servis sağlayıcıyı kullanarak servisleri alabilir ve yapılandırabilirsiniz.
    var someService = serviceProvider.GetRequiredService<ISomeService>();
    // Yapılacak işlemler...
}
2. Servis Bağlamı Erişimi (Accessing Service Container)

Startup sınıfından bağımsız bileşenlerde servislerin yapılandırılması için IServiceProvider arayüzüne erişim sağlayabilirsiniz. Bu özellikle uygulamanın başka bir yerinde (örneğin, bir servis içerisinde) servis ihtiyacınız olduğunda kullanışlıdır.

public class SomeService : ISomeService
{
    private readonly IServiceProvider _serviceProvider;

    public SomeService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void DoSomething()
    {
        // Servis bağlamından bir servis alınabilir.
        var otherService = _serviceProvider.GetRequiredService<IOtherService>();
        // Yapılacak işlemler...
    }
}
3. Servis Yapılandırması Değişiklikleri (Service Configuration Changes)

Servislerin yapılandırılmasını etkilemek için, ConfigureServices yöntemi içinde değişiklikler yapabilirsiniz. Örneğin, belirli bir ortamda veya koşul altında farklı servis yapılandırmaları yapabilirsiniz.

public void ConfigureServices(IServiceCollection services)
{
    // Ortama bağlı olarak farklı servislerin kaydedilmesi
    if (Environment.IsDevelopment())
    {
        services.AddTransient<ISomeService, DevelopmentSomeService>();
    }
    else
    {
        services.AddTransient<ISomeService, ProductionSomeService>();
    }
}

Bu yöntemler, ASP.NET Core’da dependency injection yapılandırması için alternatif yaklaşımlar sağlar. Projelerinizin ihtiyaçlarına ve karmaşıklığına bağlı olarak, bu yöntemlerden birini veya birkaçını bir arada kullanabilirsiniz.

Using Dependency Injection in ASP.NET Core

How to inject services into a controller

ASP.NET Core’da servislerin bir denetleyiciye (controller) enjekte edilmesi, dependency injection (bağımlılık enjeksiyonu) kullanılarak gerçekleştirilir. Bu, bir denetleyici sınıfının kurucu işlevine gerekli servisleri parametre olarak alarak yapılır.

Adım 1: Servislerin Kaydedilmesi

Öncelikle, servislerin uygulamanın servis bağlamına kaydedilmesi gerekmektedir. Bu işlem genellikle Startup.cs dosyasındaki ConfigureServices yönteminde yapılır.

Örnek olarak:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyServiceImplementation>();
}

Yukarıdaki kod, IMyService arabirimine karşılık gelen bir hizmetin (MyServiceImplementation) kaydedilmesini sağlar. Transient metodu, her istendiğinde yeni bir örnek oluşturulacağını belirtir.

Adım 2: Servislerin Denetleyiciye Enjekte Edilmesi

Denetleyicilere servislerin enjekte edilmesi, denetleyici sınıfının kurucu işlevine gerekli servislerin parametre olarak eklenmesiyle yapılır.

Örnek olarak:

public class MyController : ControllerBase
{
    private readonly IMyService _myService;

    public MyController(IMyService myService)
    {
        _myService = myService;
    }

    // Diğer action metotları...
}

Yukarıdaki kodda, MyController sınıfı IMyService tipinde bir servis olan _myService özelliğine sahiptir. Kurucu işlev, IMyService türündeki bir servisin enjekte edilmesini bekler. Bu, _myService özelliğinin kullanılabilir olmasını sağlar.

Adım 3: Servislerin Kullanılması

Servisler artık denetleyici içinde kullanılabilir durumdadır. Denetleyicinin herhangi bir işlevinde bu servislerin yöntemlerine veya özelliklerine erişebilirsiniz.

Örnek olarak:

public class MyController : ControllerBase
{
    private readonly IMyService _myService;

    public MyController(IMyService myService)
    {
        _myService = myService;
    }

    public IActionResult MyAction()
    {
        var result = _myService.DoSomething();
        return Ok(result);
    }
}

Yukarıdaki örnek, MyAction adlı bir işlev içinde _myService servisinin DoSomething() metodunu çağırır ve sonucunu bir HTTP yanıtı olarak döndürür.

Bu adımları takip ederek, ASP.NET Core uygulamanızda servislerin denetleyicilere nasıl enjekte edileceğini başarılı bir şekilde gerçekleştirebilirsiniz. Bu yaklaşım, kodunuzu daha modüler, daha okunabilir ve daha test edilebilir hale getirir.

Inject services in other components of a web application

ASP.NET Core’da, bir web uygulamasının denetleyicileri (controllers) dışında diğer bileşenlerde de servislerin (dependencies) enjekte edilmesi, dependency injection (bağımlılık enjeksiyonu) kullanılarak gerçekleştirilir. Bu, servislerin diğer bileşenlerin kurucu işlevlerine parametre olarak geçirilmesiyle yapılır.

Adım 1: Servislerin Kaydedilmesi

Öncelikle, servislerin uygulamanın servis bağlamına kaydedilmesi gerekmektedir. Bu işlem genellikle Startup.cs dosyasındaki ConfigureServices yönteminde yapılır.

Örnek olarak:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyServiceImplementation>();
}

Yukarıdaki kod, IMyService arabirimine karşılık gelen bir servisin (MyServiceImplementation) kaydedilmesini sağlar. Transient metodu, her istendiğinde yeni bir örnek oluşturulacağını belirtir.

Adım 2: Servislerin Diğer Bileşenlere Enjekte Edilmesi

Servislerin diğer bileşenlere enjekte edilmesi, bu bileşenlerin kurucu işlevlerine gerekli servislerin parametre olarak eklenmesiyle yapılır.

2.1. Servislerin Servisler (Services) Sınıfına Enjekte Edilmesi
public class SomeService
{
    private readonly IMyService _myService;

    public SomeService(IMyService myService)
    {
        _myService = myService;
    }

    public void DoSomething()
    {
        // _myService'i kullanarak işlemler yapın
    }
}

Yukarıdaki kod, SomeService sınıfının kurucu işlevine IMyService tipinde bir servis olan _myService‘i enjekte eder. Bu, SomeService sınıfının DoSomething() metodu içinde _myService servisinin kullanılabilir olmasını sağlar.

2.2. Servislerin Middleware’lere Enjekte Edilmesi
public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMyService _myService;

    public MyMiddleware(RequestDelegate next, IMyService myService)
    {
        _next = next;
        _myService = myService;
    }

    public async Task Invoke(HttpContext context)
    {
        // _myService'i kullanarak işlemler yapın
        await _next(context);
    }
}

Yukarıdaki örnek, bir middleware bileşeni olan MyMiddleware sınıfının kurucu işlevine IMyService tipinde bir servis olan _myService‘i enjekte eder. Bu, middleware’in Invoke yönteminde _myService servisinin kullanılabilir olmasını sağlar.

Sonuç

Yukarıdaki adımları takip ederek, ASP.NET Core uygulamanızın farklı bileşenlerinde servislerin nasıl enjekte edileceğini başarılı bir şekilde gerçekleştirebilirsiniz. Bu yaklaşım, kodunuzu daha modüler, daha okunabilir ve daha test edilebilir hale getirir.

How to set up a hosted service

ASP.NET Core’da barındırılan servisler (hosted services), arka planda periyodik olarak çalışan ve uygulamanızın ömrü boyunca çalışan arka plan işlemlerini yönetmek için kullanılır. Bu, örneğin, periyodik görevlerin yürütülmesi, zamanlayıcıların veya arka plan işlemlerinin izlenmesi gibi senaryolar için idealdir.

Adım 1: IHostedService Arabirimini Uygulama

Barındırılan servis oluşturmak için öncelikle Microsoft.Extensions.Hosting ad alanındaki IHostedService arabirimini uygulayan bir sınıf oluşturmanız gerekmektedir.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

public class MyHostedService : IHostedService, IDisposable
{
    private Timer _timer;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        // Bu metot periyodik olarak çalışacak işlemleri içerir
        Console.WriteLine("Hosted service is running...");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

Yukarıdaki kod, IHostedService arabirimini uygulayan ve StartAsync ve StopAsync metodlarını içeren MyHostedService adlı bir sınıfı göstermektedir. Bu sınıf, StartAsync metodu çağrıldığında başlatılacak ve StopAsync metodu çağrıldığında durdurulacak bir zamanlayıcıyı (Timer) kullanarak bir iş parçacığını periyodik olarak çalıştırmaktadır.

Adım 2: Servis Kaydı

Oluşturduğunuz barındırılan servisi, uygulama servis bağlamına kaydetmeniz gerekmektedir. Bu genellikle Startup.cs dosyasındaki ConfigureServices yönteminde yapılır.

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<MyHostedService>();
}

Yukarıdaki kod, MyHostedService sınıfını barındırılan bir servis olarak kaydeder. Bu, uygulama başladığında bu barındırılan servisin otomatik olarak başlayacağı anlamına gelir.

Sonuç

Yukarıdaki adımları takip ederek, ASP.NET Core uygulamanızda bir barındırılan servis oluşturabilir ve kullanabilirsiniz. Bu yaklaşım, arka planda periyodik işlemlerin yürütülmesi gibi senaryolar için oldukça kullanışlıdır ve uygulamanızın performansını ve işlevselliğini artırabilir.

Disposing of a service

ASP.NET Core’da, servislerin kullanım ömrü boyunca yönetilmesi önemlidir. Özellikle, belirli bir servisin artık kullanılmadığı ve kaynakların serbest bırakılması gerektiği durumları ele almak önemlidir. Bu işlem, servislerin uygun bir şekilde sonlandırılması (disposing) olarak adlandırılır.

IDisposable Arabirimi Kullanma

.NET platformunda, IDisposable arabirimi, bir nesnenin kaynaklarını serbest bırakmak için kullanılır. ASP.NET Core’da, IDisposable arabirimini uygulayan bir servis oluşturarak ve IDisposable.Dispose yöntemini kullanarak kaynakları serbest bırakabiliriz.

Örnek bir servis:

public class MyDisposableService : IDisposable
{
    private bool _disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Managed kaynakları serbest bırak
            }

            // Unmanaged kaynakları serbest bırak

            _disposed = true;
        }
    }

    // Opsiyonel olarak, finalize yöntemi
    ~MyDisposableService()
    {
        Dispose(false);
    }
}

Yukarıdaki örnekte, IDisposable arabirimini uygulayan ve IDisposable.Dispose yöntemini kullanarak kaynakları serbest bırakan bir servis sınıfı gösterilmektedir. IDisposable.Dispose yöntemi, managed ve unmanaged kaynakları serbest bırakır ve nesnenin garbage collector tarafından yeniden kullanılabilmesi için suppressFinalize() yöntemi çağrılır.

Servis Kullanımı

Bu IDisposable arabirimini uygulayan servisi kullanırken, genellikle servisin uygulama tarafından kullandığı yerde IDisposable.Dispose yöntemini çağırmak önemlidir. Bu, kaynakların zamanında serbest bırakılmasını sağlar.

Örnek bir kullanım:

public class SomeController : ControllerBase
{
    private readonly MyDisposableService _service;

    public SomeController(MyDisposableService service)
    {
        _service = service;
    }

    public IActionResult SomeAction()
    {
        try
        {
            // Servisi kullan
        }
        finally
        {
            // Servisin kaynaklarını serbest bırak
            _service.Dispose();
        }
    }
}

Yukarıdaki kodda, SomeController sınıfında MyDisposableService tipinde bir servis kullanılırken, SomeAction işlevinde IDisposable.Dispose yöntemi çağrılarak servisin kaynakları serbest bırakılır.

Sonuç

ASP.NET Core’da, IDisposable arabirimi kullanarak bir servisin kaynaklarını serbest bırakmak önemlidir. Bu, servislerin bellek sızıntılarına ve kaynak tükenmesine karşı korunmasını sağlar ve uygulamanın performansını ve güvenilirliğini artırır. Yukarıdaki adımları takip ederek, ASP.NET Core uygulamanızda IDisposable arabirimini kullanarak servislerinizi uygun şekilde sonlandırabilirsiniz.

Common Errors

Forgetting to add a service

ASP.NET Core uygulamalarında, dependency injection kullanırken sıkça karşılaşılan hatalardan biri, bir servisi uygulamaya kaydetmeyi (register) unutmaktır. Bu hata, uygulama çalışırken servislerin doğru şekilde çözümlenememesine ve dolayısıyla çalışma zamanı hatalarına neden olabilir.

Hatanın Tanımı

Bir servisin kaydedilmemesi, uygulama çalıştığında bu servisin çözümlenememesine yol açar. Bu durumda, ASP.NET Core çalışma zamanı hatası üretebilir. Örneğin, bir servis kullanılmadan önce kaydedilmediyse, çözümleme (resolve) işlemi sırasında InvalidOperationException gibi bir hata alınabilir.

Hata Örnekleri
Hata: Servis Kaydedilmedi
public class SomeController : ControllerBase
{
    private readonly IMyService _myService;

    public SomeController(IMyService myService)
    {
        _myService = myService;
    }

    public IActionResult SomeAction()
    {
        _myService.DoSomething(); // Hata: myService çözümlenemedi
        return Ok();
    }
}

Yukarıdaki örnekte, SomeController sınıfı bir IMyService servisi alır, ancak bu servis uygulamada kaydedilmediği için çözümlenemez.

Çözüm

Servislerin doğru şekilde çözümlenmesi için, ConfigureServices() yöntemi içinde servisleri kaydetmeyi unutmamalısınız. Aşağıdaki gibi bir örnek gösterilmektedir:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyServiceImplementation>(); // IMyService servisini kaydet
}

Yukarıdaki örnekte, IMyService arabirimine karşılık gelen MyServiceImplementation servisinin kaydedildiği gösterilmektedir. Bu, uygulama çalıştırıldığında IMyService türündeki servislerin çözümlenebileceği anlamına gelir.

Sonuç

Bir servisin uygulamaya kaydedilmemesi, dependency injection kullanıldığında sık karşılaşılan bir hatadır ve uygulama çalışma zamanında hatalara neden olabilir. Bu hatayı önlemek için, servislerin ConfigureServices() yöntemi içinde doğru şekilde kaydedildiğinden emin olmalısınız. Böylece, uygulamanızın başlatılması ve servislerin doğru şekilde çözümlenmesi sağlanır.

Injecting services with different service lifetimes

ASP.NET Core uygulamalarında dependency injection (bağımlılık enjeksiyonu) kullanırken karşılaşılabilecek yaygın hatalardan biri, farklı servis ömürlerine sahip servisleri yanlış şekilde enjekte etmektir. Servis ömrü, bir servisin oluşturulma, kullanım ve yok edilme sürecini tanımlar. Farklı ömürlere sahip servisleri yanlışlıkla karıştırmak, uygulamanın beklenmeyen davranışlara yol açabilecek bir hata kaynağı olabilir.

Hatanın Tanımı

Farklı servis ömürlerine sahip servisleri yanlış şekilde enjekte etmek, uygulamanın beklenmeyen davranışlara yol açabilecek bir hata kaynağıdır. Örneğin, bir servisi Scoped olarak kaydettiyseniz ve Singleton olarak enjekte etmeye çalışırsanız, bu, farklı isteklerde aynı örneğin paylaşılmasına neden olabilir.

Hata Örnekleri
Hata: Farklı Ömürlere Sahip Servisleri Yanlış Enjekte Etmek
public class SomeService
{
    private readonly IScopedService _scopedService;
    private readonly ISingletonService _singletonService;

    public SomeService(IScopedService scopedService, ISingletonService singletonService)
    {
        _scopedService = scopedService;
        _singletonService = singletonService;
    }

    public void DoSomething()
    {
        // Kullan _scopedService ve _singletonService
    }
}

Yukarıdaki örnekte, SomeService sınıfı, farklı ömürlere sahip olan IScopedService ve ISingletonService servislerini alır. Ancak, bu durum, farklı servis ömürlerini karıştırarak beklenmeyen davranışlara neden olabilir.

Çözüm

Servis ömrünü dikkate alarak servisleri doğru şekilde enjekte etmek önemlidir. Genellikle, Scoped servisleri diğer Scoped veya Transient servislere enjekte etmek uygun olurken, Singleton servislerin farklı ömürlere sahip servislere enjekte edilmesi sorunlara yol açabilir. Bu nedenle, servislerin ömrüne dikkat ederek uygun enjeksiyonu gerçekleştirmelisiniz.

Örnek
public void ConfigureServices(IServiceCollection services)
{
    // Scoped servisi kaydet
    services.AddScoped<IScopedService, ScopedServiceImplementation>();

    // Singleton servisi yanlışlıkla kaydetmek
    services.AddSingleton<ISingletonService, SingletonServiceImplementation>();
}

Yukarıdaki örnekte, Scoped servis doğru şekilde kaydedilmiştir. Ancak, yanlışlıkla Singleton servis kaydedilmiştir. Bu durum, Scoped servis tarafından kullanıldığında beklenmeyen sonuçlara yol açabilir.

Sonuç

Farklı servis ömürlerine sahip servisleri yanlış şekilde enjekte etmek, ASP.NET Core uygulamalarında sık karşılaşılan bir hatadır. Bu hata, uygulamanın beklenmeyen davranışlara ve hatalara yol açabilir. Bu nedenle, servis ömrünü dikkate alarak uygun şekilde servisleri enjekte etmek önemlidir. Bu, uygulamanın doğru şekilde çalışmasını ve beklenen sonuçları üretmesini sağlar.

Circular dependency

Dairesel bağımlılık (Circular dependency), bir servisin kendisini veya diğer bir servisi doğrudan veya dolaylı olarak içermesi durumunda ortaya çıkar. Bu durum, dependency injection (bağımlılık enjeksiyonu) kullanıldığında sıkça karşılaşılan bir hata türüdür. ASP.NET Core uygulamalarında dairesel bağımlılıklar, uygulamanın başlatılmasını veya servislerin çözümlenmesini engelleyebilir.

Hatanın Tanımı

Dairesel bağımlılık, bir servisin kendisini veya başka bir servisi doğrudan veya dolaylı olarak içermesi durumunda ortaya çıkar. Bu durum, uygulamanın servisleri çözümlenirken sonsuz döngüye girerek veya stack taşmasına neden olarak hatalara yol açar.

Hata Örnekleri
Hata: Dairesel Bağımlılık
public class ServiceA
{
    private readonly ServiceB _serviceB;

    public ServiceA(ServiceB serviceB)
    {
        _serviceB = serviceB;
    }
}

public class ServiceB
{
    private readonly ServiceA _serviceA;

    public ServiceB(ServiceA serviceA)
    {
        _serviceA = serviceA;
    }
}

Yukarıdaki örnekte, ServiceA sınıfı ServiceB’yi, ServiceB sınıfı ise ServiceA’yı içermektedir. Bu durum, dairesel bağımlılığa neden olur.

Çözüm

Dairesel bağımlılıkları çözmek için, genellikle tasarımı yeniden düzenlemek veya bağımlılıkları azaltmak gerekir. Aşağıdaki çözüm yöntemlerinden birini kullanabiliriz:

  1. Tasarımı Yeniden Düzenleme: Bağımlılıkları azaltmak için servisleri başka bir şekilde bölünerek veya yeniden düzenleyerek dairesel bağımlılığı gidermek mümkündür.
  2. İhtiyaç Halinde Yüklenme (Lazy Loading): Servislerin gerektiği anda yüklenmesini sağlamak için lazy loading (tembel yükleme) kullanılabilir. Bu, servislerin yalnızca ihtiyaç duyulduğunda yüklenmesini ve dolayısıyla dairesel bağımlılığın önlenmesini sağlar.
Örnek Çözüm
public class ServiceA
{
    private readonly Lazy<ServiceB> _lazyServiceB;

    public ServiceA(Lazy<ServiceB> lazyServiceB)
    {
        _lazyServiceB = lazyServiceB;
    }
}

public class ServiceB
{
    private readonly Lazy<ServiceA> _lazyServiceA;

    public ServiceB(Lazy<ServiceA> lazyServiceA)
    {
        _lazyServiceA = lazyServiceA;
    }
}

Yukarıdaki örnekte, Lazy<T> sınıfı kullanılarak dairesel bağımlılık çözülmüştür. Servislerin yüklenmesi gerektiğinde yalnızca ihtiyaç duyulduğunda yüklenir.

Sonuç

Dairesel bağımlılık, dependency injection kullanıldığında sıkça karşılaşılan bir hata türüdür. Bu hata, uygulamanın başlatılmasını veya servislerin çözümlenmesini engelleyebilir. Bu nedenle, dairesel bağımlılıkları önlemek veya çözmek için tasarımı yeniden düzenlemek veya diğer çözüm yöntemlerini kullanmak önemlidir. Bu, uygulamanın doğru şekilde çalışmasını sağlar ve beklenen davranışı elde etmenizi sağlar.

Ambiguous constructors

ASP.NET Core uygulamalarında, dependency injection (bağımlılık enjeksiyonu) kullanırken sıkça karşılaşılan hatalardan biri, belirsiz (ambiguous) kurucuların bulunmasıdır. Bu durum, bir hizmetin birden fazla kurucusunun olması durumunda ortaya çıkar ve ASP.NET Core’un hizmetleri nasıl çözümleyeceğini belirlemekte güçlük çeker.

Hatanın Tanımı

Belirsiz kurucuların bulunması durumunda, dependency injection çözümleyicisi hangi kurucuyu kullanması gerektiğini belirleyemez. Bu durumda, hangi kurucunun kullanılacağı belirsizdir ve bu, uygulamanın başlatılmasını engelleyebilir.

Hata Örnekleri
Hata: Belirsiz Kurucular
public class MyService
{
    public MyService()
    {
        // ...
    }

    public MyService(IServiceA serviceA)
    {
        // ...
    }

    public MyService(IServiceB serviceB)
    {
        // ...
    }
}

Yukarıdaki örnekte, MyService sınıfının birden fazla kurucusu bulunmaktadır. Bu durum, dependency injection çözümleyicisinin hangi kurucuyu kullanması gerektiğini belirlemekte zorlanmasına neden olur.

Çözüm

Belirsiz kurucuların bulunmasını önlemek için aşağıdaki adımları izleyebiliriz:

  1. Tek Bir Kurucu Kullanma: Bir sınıfın yalnızca bir kurucusunun olmasını sağlamak en iyi uygulama yöntemidir. Birden fazla kurucu kullanımı gerekiyorsa, bu durumu yeniden düzenlemek genellikle daha iyi bir tasarım yaklaşımı olabilir.
  2. Kurucuları Parametrelerle Ayırma: Birden fazla kurucuya sahip olmak zorunda kalırsak, kurucuları parametrelerle birbirinden ayırmak önemlidir. Böylece dependency injection çözümleyicisi hangi kurucunun kullanılacağını daha kolay belirleyebilir.
Örnek Çözüm
public class MyService
{
    private readonly IServiceA _serviceA;
    private readonly IServiceB _serviceB;

    public MyService(IServiceA serviceA)
    {
        _serviceA = serviceA;
    }

    public MyService(IServiceB serviceB)
    {
        _serviceB = serviceB;
    }
}

Yukarıdaki örnekte, MyService sınıfının iki ayrı kurucusu vardır, ancak her biri farklı bir servisi alır. Bu durum, dependency injection çözümleyicisinin hangi kurucuyu kullanması gerektiğini belirlemesini kolaylaştırır.

Sonuç

Belirsiz kurucuların bulunması, dependency injection kullanırken sıkça karşılaşılan bir hata türüdür. Bu hata, dependency injection çözümleyicisinin hangi kurucuyu kullanması gerektiğini belirlemekte güçlük çeker. Bu nedenle, bir sınıfın yalnızca bir kurucuya sahip olmasını sağlamak veya kurucuları parametrelerle ayırarak bu tür hataları önlemek önemlidir. Bu, uygulamanın başarılı bir şekilde başlatılmasını ve servislerin doğru şekilde çözümlenmesini sağlar.

Siz kendinize inanın, başkaları da size inanacaktır.

Goethe

Bir sonraki yazıda görüşmek dileğiyle!”

Leave a Reply

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir


10 + 9 = ?