Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Note
Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.
Warning
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.
Kirk Larkin, Steve Smith ve Brandon Dahler tarafından
ASP.NET Core, sınıflar ve onların bağımlılıkları arasında Denetimin Tersini (IoC) sağlamak için bir teknik olarak bağımlılık ekleme (DI) yazılım tasarımı desenini destekler.
Bu makalede, ASP.NET Core web uygulamalarında DI hakkında bilgi sağlanır. Web uygulamaları dışındaki uygulamalar da dahil olmak üzere tüm uygulama türlerinde DI hakkında bilgi için bkz. .NET'te bağımlılık ekleme.
Bu makaledeki yönergeleri tamamlayan veya bunların yerine geçen yönergeler aşağıdaki makalelerde bulunur:
- ASP.NET Core Blazor bağımlılık ekleme
- ASP.NET Core'daki denetleyicilere bağımlılık ekleme
- Seçenekleri yapılandırmak için DI hizmetlerini kullanma
Bu makaledeki kod örnekleri Blazor temel alır. Sayfa örneklerini görmek Razor için bu makalenin 7.0 sürümüne bakın.
Örnek kodu görüntüleme veya indirme (indirme)
Bu makaledeki örnek kodu gösterim amacıyla yerel Blazor Web App bir kodda kullanırken etkileşimli işleme modunu benimseyin.
Bağımlılık enjeksiyonuna genel bakış
Bağımlılık, başka bir nesnenin bağımlı olduğu bir nesnedir. Aşağıdaki MyDependency sınıfı bir WriteMessage yöntemle göz önünde bulundurun:
public class MyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage: {message}");
}
}
Bir sınıf, MyDependency sınıfının bir örneğini oluşturabilir ve WriteMessage yöntemini çağırabilir. Aşağıdaki örnekte MyDependency sınıfı bir Razor bileşeninin bağımlılığıdır.
Pages/DependencyExample1.razor:
@page "/dependency-example-1"
<button @onclick="WriteMessage">Write message</button>
@code {
private readonly MyDependency dependency = new MyDependency();
private void WriteMessage() =>
dependency.WriteMessage("DependencyExample1.WriteMessage called");
}
Bir sınıf, WriteMessage yöntemini çağırmak için MyDependency sınıfının bir örneğini oluşturabilir. Aşağıdaki örnekte, MyDependency sınıfı bir sayfa sınıfının bağımlılığıdır IndexModel .
Pages/Index.cshtml.cs:
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency();
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet called");
}
}
Tüketen sınıf oluşturur ve doğrudan MyDependency sınıfına bağlıdır. Önceki örnekte olduğu gibi doğrudan bağımlılık almak sorunludur ve aşağıdaki nedenlerden dolayı kaçınılmalıdır:
- Farklı bir uygulamayla
MyDependencyöğesini değiştirmek için, tüketen sınıfın değiştirilmesi gerekir. - Bağımlılıkları varsa
MyDependency, bunlar da kullanan sınıf tarafından yapılandırılmalıdır. bağlı olarakMyDependencybirden çok sınıfa sahip büyük bir projede yapılandırma kodu uygulamanın etrafına dağılır. - Uygulamanın birim testi yapmak zor.
DI bu sorunları şu şekilde giderir:
- Bağımlılık uygulamasını soyutlama amacıyla bir arabirim veya temel sınıf kullanımı.
- Di kapsayıcısı olarak da adlandırılan bir hizmet kapsayıcısındabağımlılığın kaydı. ASP.NET Core yerleşik bir hizmet kapsayıcısı sağlar: IServiceProvider. Hizmetler genellikle uygulamanın
Programdosyasına (.NET 6 veya üzeri) veya uygulamanınStartupdosyasına (.NET 5 veya öncesi) kaydedilir. - Hizmetin kullanıldığı sınıflara enjekte edilmesi. Çerçeve, bağımlılıkların örneklerini oluşturur ve artık gerekli olmadığında bunları atar.
Aşağıdaki örnekte, IMyDependency arabirim yöntem imzasını WriteMessage tanımlar.
Interfaces/IMyDependency.cs:
public interface IMyDependency
{
void WriteMessage(string message);
}
Yukarıdaki arabirim, aşağıdaki somut tür MyDependency tarafından uygulanır.
Services/MyDependency.cs:
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage: {message}");
}
}
Uygulama, IMyDependency hizmetini, hizmetlerin genellikle Program dosyasında (.NET 6 veya üzeri) veya Startup.ConfigureServices yönteminde (.NET 5 veya daha önceki) hizmet kapsayıcısına eklendiği belirli tür MyDependency ile kaydeder.
AddScoped yöntemi, hizmeti, .NET 8 veya üzerindeki bir devre ömrüyle ya da bir MVC veya Pages uygulamasındaki tek bir isteğin süreli yaşam döngüsüyle kaydeder.
Hizmet yaşam süreleri bu makalenin devamında açıklanmıştır.
builder.Services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency, MyDependency>();
Aşağıdaki Razor bileşeninde gösterildiği gibi, IMyDependency hizmeti istenir ve WriteMessage yöntemini çağırmak için kullanılır.
Pages/DependencyExample2.razor:
@page "/dependency-example-2"
@inject IMyDependency Dependency
<button @onclick="WriteMessage">Write message</button>
@code {
private void WriteMessage() =>
Dependency.WriteMessage("DependencyExample2.WriteMessage called");
}
IMyDependency hizmeti istenir ve WriteMessage yöntemini çağırmak için kullanılır, aşağıdaki sayfa modeli sınıfının gösterdiği gibi.
Pages/Index.cshtml.cs:
public class IndexModel(IMyDependency dependency) : PageModel
{
public void OnGet()
{
dependency.WriteMessage("IndexModel.OnGet called");
}
}
DI desenini kullanarak, bağımlılığı tüketen sınıf:
- Somut tür
MyDependencykullanılmaz, yalnızca uyguladığıIMyDependencyarabirimi kullanılır. Bu, tüketiciyi değiştirmeden uygulamayı değiştirmeyi kolaylaştırır. - Doğrudan bir
MyDependencyörneği oluşturmaz veya bertaraf etmez. Bağımlılık, hizmet kapsayıcısı tarafından oluşturulur ve yok edilir.
Arabirim IMyDependency uygulaması, aşağıdaki örnekte bağımlılık olarak eklenen yerleşik günlük API'sini kullanarak geliştirilebilir.
Services/MyDependency.cs:
public class MyDependency(ILogger<MyDependency> logger) : IMyDependency
{
public void WriteMessage(string message)
{
logger.LogInformation($"MyDependency.WriteMessage: {message}");
}
}
MyDependency
ILogger<TCategoryName>, çerçeve tarafından sağlanan bir hizmete bağlıdır.
DI'yi zincirleme bir şekilde kullanmak yaygın bir durum. İstenen her bağımlılık da kendi bağımlılıklarını istemektedir. Kapsayıcı, grafikteki bağımlılıkları çözer ve tam olarak çözümlenen hizmeti döndürür. Çözülmesi gereken ortak bağımlılık kümesi genellikle bağımlılık ağacı, bağımlılık grafı veya nesne grafı olarak adlandırılır.
Kapsayıcı, ILogger<TCategoryName> (genel) açık türlerden yararlanarak, her (genel) oluşturulmuş türü kaydettirme gereksinimini ortadan kaldırır.
DI terminolojisinde bir hizmet:
- Genellikle önceki
IMyDependencyhizmet gibi diğer nesnelere hizmet sağlayan bir nesnedir. - Bir web hizmetiyle ilgili değildir, ancak hizmet bir web hizmeti kullanabilir.
IMyDependency Önceki örneklerde yer alan uygulamalar, günlüğe kaydetme uygulamak için değil, genel DI ilkelerini göstermek için yazılmıştır. Önceki örneklerde gösterildiği gibi çoğu uygulamanın günlükçü oluşturması gerekmez. Aşağıdaki kod, çerçevenin özel bir hizmetin () kaydedilmesini gerektirmeyen IMyDependency kullanılmasını doğrudan gösterir.
Pages/LoggingExample.razor:
@page "/logging-example"
@inject ILogger<LoggingExample> Logger
<button @onclick="WriteMessage">Write message</button>
@code {
private void WriteMessage() =>
Logger.LogInformation("LoggingExample.WriteMessage called");
}
Pages/IndexModel.cshtml.cs:
public class IndexModel(ILogger<IndexModel> logger) : PageModel
{
public void OnGet()
{
logger.LogInformation("IndexModel.OnGet called");
}
}
Startup içine enjekte edilen hizmetler
Hizmetler Startup oluşturucusuna ve Startup.Configure yöntemine enjekte edilebilir.
ASP.NET Core 3.0 veya sonraki sürümlerin Genel Ana Bilgisayarı (IHostBuilder), geçici bir "kök" hizmet sağlayıcısının uygulamanın ana hizmet kapsayıcısını başlatmak ve yapılandırmak için ana bilgisayar için temel hizmetleri kullanması sonrasında uygulamanın yaşam döngüsü boyunca tek bir hizmet kapsayıcısı kullanır. Ana bilgisayar başlatma işlemine dahil olmayan özel hizmetler ve çerçeve hizmetleri de dahil olmak üzere hizmetlerin çoğu, Startup yapıcısı çağrıldığında hizmet kapsayıcısında yapılandırılmamış ya da mevcut değildir. Genel Host kullanılırken oluşturucuya yalnızca aşağıdaki hizmetler enjekte edilebilir:
Genel Konak, sınıf oluşturucusunda Startup kullanılabilir hizmetleri kısıtlayarak, bir hizmeti oluşturulmadan veya kullanılabilir duruma gelmeden önce kullanmaya çalışmanızı ve geçici hizmet kapsayıcısında oluşturulan tek bir hizmetin son hizmet kapsayıcısında oluşturulan hizmetten farklı olabileceği özel veya çerçeve tekli hizmetlerinin birden çok örneğini oluşturmanızı engeller.
Hizmet kapsayıcısına kayıtlı herhangi bir hizmet, Startup.Configure yöntemine enjekte edilebilir. Aşağıdaki örnekte, bir ILogger<TCategoryName> eklenir:
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
...
}
Daha fazla bilgi için bkz. ASP.NET Core'da uygulama başlatma ve Startup sınıfında erişim yapılandırması.
Hizmet kayıt yöntemleri
Hizmet kayıtları hakkında genel yönergeler için bkz. Hizmet kaydı.
Test için mock türleri oluşturulurken birden fazla uygulamanın kullanılması yaygın bir durumdur. Daha fazla bilgi için bkz . ASP.NET Core'da tümleştirme testleri.
Bir hizmeti yalnızca uygulama türüyle kaydetmek, hizmeti aynı uygulama ve hizmet türüyle kaydetmeye eşdeğerdir:
builder.Services.AddSingleton<MyDependency>();
services.AddSingleton<MyDependency>();
Hizmet kayıt yöntemleri, aynı hizmet türündeki birden çok hizmet örneğini kaydetmek için kullanılabilir. Aşağıdaki örnekte, AddSingleton hizmet türü olarak ile IMyDependency iki kez çağrılır. İkinci kez AddSingleton çözümlendiğinde önceki çağrıyı IMyDependency geçersiz kılar ve birden çok hizmet IEnumerable<IMyDependency> aracılığıyla çözümlendiğinde önceki çağrıya ekler.
builder.Services.AddSingleton<IMyDependency, MyDependency>();
builder.Services.AddSingleton<IMyDependency, DifferentDependency>();
public class MyService
{
public MyService(IMyDependency myDependency,
IEnumerable<IMyDependency> myDependencies)
{
Trace.Assert(myDependency is DifferentDependency);
var dependencyArray = myDependencies.ToArray();
Trace.Assert(dependencyArray[0] is MyDependency);
Trace.Assert(dependencyArray[1] is DifferentDependency);
}
}
services.AddSingleton<IMyDependency, MyDependency>();
services.AddSingleton<IMyDependency, DifferentDependency>();
public class MyService
{
public MyService(IMyDependency myDependency,
IEnumerable<IMyDependency> myDependencies)
{
Trace.Assert(myDependency is DifferentDependency);
var dependencyArray = myDependencies.ToArray();
Trace.Assert(dependencyArray[0] is MyDependency);
Trace.Assert(dependencyArray[1] is DifferentDependency);
}
}
Uzantı yöntemleriyle hizmet gruplarını kaydetme
ASP.NET Core çerçevesinde bir grup ilgili hizmeti kaydetme kuralı, bir çerçeve özelliğinin gerektirdiği tüm hizmetleri kaydetmek için, {GROUP NAME} yer tutucusu açıklayıcı bir grup adı olan tek bir Add{GROUP NAME} uzantı yönteminin kullanılmasını içerir. Örneğin, AddRazorComponents uzantı yöntemi, Razor bileşenlerin sunucu tarafında işlenmesi için gereken hizmetleri kaydeder.
Seçenekleri yapılandıran ve hizmetleri kaydeden aşağıdaki örneği göz önünde bulundurun:
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
builder.Configuration.GetSection(ColorOptions.Color));
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();
services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>(
builder.Configuration.GetSection(ColorOptions.Color));
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
İlgili kayıt grupları, hizmetleri kaydetmek için bir uzantı yöntemine taşınabilir. Aşağıdaki örnekte:
- uzantı yöntemi,
AddConfigyapılandırma verilerini kesin olarak türü belirlenmiş C# sınıflarına bağlar ve sınıfları hizmet kapsayıcısına kaydeder. -
AddDependencyGroupuzantı yöntemi ek sınıf (hizmet) bağımlılıkları ekler.
namespace Microsoft.Extensions.DependencyInjection;
public static class ConfigServiceCollectionExtensions
{
public static IServiceCollection AddConfig(
this IServiceCollection services, IConfiguration config)
{
services.Configure<PositionOptions>(
config.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>(
config.GetSection(ColorOptions.Color));
return services;
}
public static IServiceCollection AddDependencyGroup(
this IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
return services;
}
}
Aşağıdaki kod, hizmetleri kaydetmek için önceki AddConfig ve AddDependencyGroup uzantı yöntemlerini çağırır:
builder.Services
.AddConfig(builder.Configuration)
.AddDependencyGroup();
services
.AddConfig(builder.Configuration)
.AddDependencyGroup();
Uygulamalar için Microsoft.Extensions.DependencyInjection ad alanında uzantı yöntemleri oluşturma adlandırma kuralına uymalarını öneririz.
- Servis kayıt gruplarını kapsar.
- Hizmete uygun IntelliSense erişimi sağlar.
Hizmet ömrü
Hizmet ömrü hakkında genel yönergeler için bkz. Hizmet ömrü. Uygulamalar için geçerli olan ek hizmet ömrü kılavuzu için Blazor bkz. ASP.NET Core Blazor bağımlılık ekleme.
Ara yazılımda kapsamlı hizmetleri kullanmak için aşağıdaki yaklaşımlardan birini kullanın:
- Hizmeti ara yazılımının
InvokeveyaInvokeAsyncyöntemine ekleyin. Oluşturucu enjeksiyonu kullanılması, kapsamı belirlenmiş hizmeti tekil gibi davranmaya zorladığı için bir çalışma zamanı özel durumu fırlatır. Yaşam süresi ve kayıt seçenekleri bölümündeki örnekyaklaşımını göstermektedir. - Fabrika tabanlı ara yazılımı kullanın. Bu yaklaşım kullanılarak kaydedilen ara yazılım, her istemci isteği (bağlantı) başına etkinleştirilir ve bu, kapsamı belirlenmiş hizmetlerin ara yazılımın yapıcısına enjekte edilmesini sağlar.
Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:
- Özel ASP.NET Core ara yazılımı yazma
- Anahtarlı hizmetleri Razor bileşenlerle kullanma hakkında daha fazla bilgi için bkz. ASP.NET Core Blazor bağımlılık enjeksiyonu.
Anahtarlı hizmetler
Anahtarlı hizmetler anahtarları kullanarak hizmetleri kaydeder ve alır. Bir hizmet, hizmet kaydı için aşağıdaki uzantı yöntemlerinden herhangi birini çağırarak bir anahtarla ilişkilendirilir:
Aşağıdaki örnekte aşağıdaki API ile anahtarlı hizmetler gösterilmektedir:
-
IStringCache, yöntem imzası olanGethizmet arabirimidir. -
StringCache1veStringCache2içinIStringCachesomut hizmet uygulamalarıdır.
Interfaces/IStringCache.cs:
public interface IStringCache
{
string Get(int key);
}
Services/StringCache1.cs:
public class StringCache1 : IStringCache
{
public string Get(int key) => $"Resolving {key} from StringCache1.";
}
Services/StringCache2.cs:
public class StringCache2 : IStringCache
{
public string Get(int key) => $"Resolving {key} from StringCache2.";
}
özniteliğine sahip anahtarı belirterek kayıtlı bir hizmete erişin[FromKeyedServices].
Anahtarlı hizmet ve dosyadaki Program minimum API uç noktaları örneği:
builder.Services.AddKeyedSingleton<IStringCache, StringCache1>("cache1");
builder.Services.AddKeyedSingleton<IStringCache, StringCache2>("cache2");
...
app.MapGet("/cache1", ([FromKeyedServices("cache1")] IStringCache stringCache1) =>
stringCache1.Get(1));
app.MapGet("/cache2", ([FromKeyedServices("cache2")] IStringCache stringCache2) =>
stringCache2.Get(2));
Razor bileşeninde (Pages/KeyedServicesExample.razor), [Inject] özelliğini kullanan örnek kullanım.
InjectAttribute.Key Hizmetin eklenecek anahtarını belirtmek için özelliğini kullanın:
@page "/keyed-services-example"
@Cache?.Get(3)
@code {
[Inject(Key = "cache1")]
public IStringCache? Cache { get; set; }
}
Anahtarlı hizmetleri Razor bileşenlerle kullanma hakkında daha fazla bilgi için bkz. ASP.NET Core Blazor bağımlılık enjeksiyonu.
Birincil oluşturucu eklemeli bir SignalR hub'da (Hubs/MyHub1.cs) örnek kullanım:
using Microsoft.AspNetCore.SignalR;
public class MyHub1([FromKeyedServices("cache2")] IStringCache cache) : Hub
{
public void Method()
{
Console.WriteLine(cache.Get(4));
}
}
Yöntem ekleme ile hub'da SignalR (Hubs/MyHub2.cs) kullanım örneği:
using Microsoft.AspNetCore.SignalR;
public class MyHub2 : Hub
{
public void Method([FromKeyedServices("cache2")] IStringCache cache)
{
Console.WriteLine(cache.Get(5));
}
}
Orta katman, hem orta katmanın oluşturucusunda hem de Invoke/InvokeAsync yönteminde anahtarlı hizmetleri destekler.
internal class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next,
[FromKeyedServices("cache1")] IStringCache cache)
{
_next = next;
Console.WriteLine(cache.Get(6));
}
public Task Invoke(HttpContext context,
[FromKeyedServices("cache2")] IStringCache cache)
{
Console.WriteLine(cache.Get(7));
return _next(context);
}
}
Dosyanın Program (.NET 6 veya üzeri) veya yönteminin Startup.Configure (.NET 5 veya öncesi) uygulama işleme hattında:
app.UseMiddleware<MyMiddleware>();
Ara yazılım oluşturma hakkında daha fazla bilgi için Özel ASP.NET Core ara yazılımı yazma bölümüne bkz.
Yapıcı enjeksiyon davranışı
Oluşturucu ekleme davranışı hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:
Entity Framework bağlamları
Sunucu tarafı uygulamalarda yönergeler EF Core için bkz. EF Core.
Varsayılan olarak, Web uygulaması veritabanı işlemlerinin kapsamı normalde istemci isteğine göre belirlenmiş olduğundan, Entity Framework bağlamları kapsamlı yaşam süresi kullanılarak hizmet kapsayıcısına eklenir. Farklı bir yaşam süresi kullanmak için, bir AddDbContext aşırı yükleme kullanarak yaşam süresi belirtin. Belirli bir yaşam süresine sahip hizmetler, hizmetin ömründen daha kısa olan bir veritabanı bağlamı kullanmamalıdır.
Yaşam süresi ve kayıt seçenekleri
Hizmet ömrü ile kayıt seçenekleri arasındaki farkı göstermek için, bir görevi tanımlayıcısı OperationIdolan bir işlem olarak temsil eden aşağıdaki arabirimleri göz önünde bulundurun. Bir işlemin hizmetinin kullanım ömrünün aşağıdaki arabirimler için nasıl yapılandırıldığına bağlı olarak, kapsayıcı bir sınıf tarafından istendiğinde hizmetin aynı veya farklı örneklerini sağlar.
IOperation.cs:
public interface IOperation
{
string OperationId { get; }
}
public interface IOperationTransient : IOperation { }
public interface IOperationScoped : IOperation { }
public interface IOperationSingleton : IOperation { }
Aşağıdaki Operation sınıf, önceki tüm arabirimleri uygular.
Operation Oluşturucu bir GUID oluşturur ve özelliğinde OperationId son dört karakteri depolar.
Operation.cs:
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
public Operation()
{
OperationId = Guid.NewGuid().ToString()[^4..];
}
public string OperationId { get; }
}
Aşağıdaki kod, adlandırılmış yaşam sürelerine göre sınıfın Operation birden çok kaydını oluşturur.
Hizmetlerin kaydedildiği yer:
builder.Services.AddTransient<IOperationTransient, Operation>();
builder.Services.AddScoped<IOperationScoped, Operation>();
builder.Services.AddSingleton<IOperationSingleton, Operation>();
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
Aşağıdaki örnekte, istekler içinde ve istekler arasında nesne yaşam süreleri gösterilmektedir. Bileşen Operation ve ara yazılım her türden istekte bulunur ve her bir IOperation türü için OperationId günlüğe kaydeder.
Pages/OperationExample.razor:
@page "/operation-example"
@inject IOperationTransient TransientOperation
@inject IOperationScoped ScopedOperation
@inject IOperationSingleton SingletonOperation
<ul>
<li>Transient: @TransientOperation.OperationId</li>
<li>Scoped: @ScopedOperation.OperationId</li>
<li>Singleton: @SingletonOperation.OperationId</li>
</ul>
Aşağıdaki örnekte, istekler içinde ve istekler arasında nesne yaşam süreleri gösterilmektedir.
IndexModel ve ara yazılım, her IOperation türü için istekte bulunur ve her biri için OperationId kaydederler.
IndexModel.cshtml.cs:
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly IOperationTransient _transientOperation;
private readonly IOperationScoped _scopedOperation;
private readonly IOperationSingleton _singletonOperation;
public IndexModel(ILogger<IndexModel> logger,
IOperationTransient transientOperation,
IOperationScoped scopedOperation,
IOperationSingleton singletonOperation)
{
_logger = logger;
_transientOperation = transientOperation;
_scopedOperation = scopedOperation;
_singletonOperation = singletonOperation;
}
public void OnGet()
{
_logger.LogInformation($"Transient: {_transientOperation.OperationId}");
_logger.LogInformation($"Scoped: {_scopedOperation.OperationId}");
_logger.LogInformation($"Singleton: {_singletonOperation.OperationId}");
}
}
Ara yazılım da aynı hizmetleri çözebilir ve kullanabilir. Kapsamlı ve geçici hizmetler InvokeAsync yönteminde/tanımlanmalıdır.
MyMiddleware.cs:
public class MyMiddleware(ILogger<IndexModel> logger,
IOperationSingleton singletonOperation)
{
public async Task InvokeAsync(HttpContext context,
IOperationTransient transientOperation, IOperationScoped scopedOperation)
{
logger.LogInformation($"Transient: {transientOperation.OperationId}");
logger.LogInformation($"Scoped: {scopedOperation.OperationId}");
logger.LogInformation($"Singleton: {singletonOperation.OperationId}");
await _next(context);
}
}
public class MyMiddleware
{
private readonly ILogger<IndexModel> _logger;
private readonly IOperationSingleton _singletonOperation;
public MyMiddleware(ILogger<IndexModel> logger,
IOperationSingleton singletonOperation)
{
_logger = logger;
_singletonOperation = singletonOperation;
}
public async Task InvokeAsync(HttpContext context,
IOperationTransient transientOperation, IOperationScoped scopedOperation)
{
_logger.LogInformation($"Transient: {transientOperation.OperationId}");
_logger.LogInformation($"Scoped: {scopedOperation.OperationId}");
_logger.LogInformation($"Singleton: {_singletonOperation.OperationId}");
await _next(context);
}
}
Dosyanın Program (.NET 6 veya üzeri) veya yönteminin Startup.Configure (.NET 5 veya öncesi) uygulama işleme hattında:
app.UseMiddleware<MyMiddleware>();
Ara yazılım oluşturma hakkında daha fazla bilgi için Özel ASP.NET Core ara yazılımı yazma bölümüne bkz.
Yukarıdaki örneklerin çıkışında şunlar gösterilir:
-
Geçici nesneler her zaman farklıdır. Geçici
OperationIddeğeri, Razor bileşeni ve ara yazılım için farklıdır. - Kapsamı belirlenmiş nesneler belirli bir istek için aynıdır, ancak yeni Blazor devreler arasında farklılık gösterir.
- Singleton nesneler her istek veya Blazor döngü için aynıdır.
-
Geçici nesneler her zaman farklıdır.
OperationIdGeçici değer, sayfa ve ara yazılım için farklıdır. - Kapsamı belirlenmiş nesneler belirli bir istek için aynıdır, ancak yeni istekler arasında farklılık gösterir.
- Singleton nesneleri her istek için aynıdır.
Uygulama başlangıcında bir hizmeti çözme
Aşağıdaki kod, uygulama başlatıldığında sınırlı bir süre için kapsamlı bir hizmetin nasıl çözümleneceğini gösterir:
var app = builder.Build();
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var dependency = services.GetRequiredService<IMyDependency>();
dependency.WriteMessage("Call services from main");
}
Kapsam doğrulaması
Kapsam doğrulaması hakkında yönergeler için aşağıdaki kaynaklara bakın:
İstek Hizmetleri
ASP.NET Core isteğindeki hizmetler ve bağımlılıkları aracılığıyla HttpContext.RequestServiceskullanıma sunulur.
Çerçeve, istek başına bir kapsam oluşturur ve RequestServices kapsamı belirlenmiş hizmet sağlayıcısını kullanıma sunar. tüm kapsamlı hizmetler, istek etkin olduğu sürece geçerlidir.
Note
RequestServices'den hizmetleri çözümlemek yerine bağımlılıkları oluşturucu parametreleri olarak istemeyi tercih edin. Oluşturucu parametreleri olarak bağımlılık istemek, test etmek daha kolay olan sınıfları verir.
Bağımlılık enjeksiyonu için hizmetler tasarlama
DI için hizmetler tasarlarken:
- Durum bilgisi olan statik sınıflardan ve üyelerden kaçının. Bunun yerine tekil hizmetleri kullanacak uygulamalar tasarlayarak genel durum oluşturmaktan kaçının.
- Hizmetlerdeki bağımlı sınıfları doğrudan örneklemeye çalışmaktan kaçının. Doğrudan örnekleme, kodu belirli bir uygulamayla eşler.
- Hizmetleri küçük, iyi faktörlü ve kolayca test edilmiş hale getirin.
Bir sınıfın çok fazla eklenmiş bağımlılığı varsa, sınıfın çok fazla sorumlulukları olduğunu ve
Hizmetlerin sonlandırılması
Kapsayıcı, oluşturduğu türler için Dispose çağrısını yapar IDisposable. Kapalı birimden çözümlenen hizmetler geliştirici tarafından asla elden çıkarılmamalıdır. Bir tür veya fabrika tekil olarak kayıtlıysa, kapsayıcı tekliyi otomatik olarak kaldırır.
Aşağıdaki örnekte, hizmetler hizmet kapsayıcısı tarafından oluşturulur ve otomatik olarak bertaraf edilir.
Services/Service1.cs:
public class Service1 : IDisposable
{
private bool _disposed;
public void Write(string message)
{
Console.WriteLine($"Service1: {message}");
}
public void Dispose()
{
if (_disposed)
{
return;
}
Console.WriteLine("Service1.Dispose");
_disposed = true;
GC.SuppressFinalize(this);
}
}
Services/Service2.cs:
public class Service2 : IDisposable
{
private bool _disposed;
public void Write(string message)
{
Console.WriteLine($"Service2: {message}");
}
public void Dispose()
{
if (_disposed)
{
return;
}
Console.WriteLine("Service2.Dispose");
_disposed = true;
GC.SuppressFinalize(this);
}
}
Services/Service3.cs:
public interface IService3
{
public void Write(string message);
}
public class Service3(string myKey) : IService3, IDisposable
{
private bool _disposed;
public void Write(string message)
{
Console.WriteLine($"Service3: {message}, Key = {myKey}");
}
public void Dispose()
{
if (_disposed)
{
return;
}
Console.WriteLine("Service3.Dispose");
_disposed = true;
GC.SuppressFinalize(this);
}
}
appsettings.Development.json'da:
"Key": "Value from appsettings.Development.json"
Hizmetlerin uygulama tarafından kaydedildiği yer:
builder.Services.AddScoped<Service1>();
builder.Services.AddSingleton<Service2>();
var key = builder.Configuration["Key"] ?? string.Empty;
builder.Services.AddSingleton<IService3>(sp => new Service3(key));
services.AddScoped<Service1>();
services.AddSingleton<Service2>();
var myKey = builder.Configuration["Key"] ?? string.Empty;
services.AddSingleton<IService3>(sp => new Service3(myKey));
Pages/DisposalExample.razor:
@page "/disposal-example"
@inject Service1 Service1
@inject Service2 Service2
@inject IService3 Service3
@code {
protected override void OnInitialized()
{
Service1.Write("DisposalExample.OnInitialized");
Service2.Write("DisposalExample.OnInitialized");
Service3.Write("DisposalExample.OnInitialized");
}
}
Hata ayıklama konsolu, Dizin sayfasının her yenilenmesinden sonra aşağıdaki çıkışı gösterir:
Service1: DisposalExample.OnInitialized
Service2: DisposalExample.OnInitialized
Service3: DisposalExample.OnInitialized, Key = Value from appsettings.Development.json
Service1.Dispose
Service1 öğesinin atılmasıyla ilgili girişi görmek için, DisposalExample bileşeninden uzaklaşarak atılmasını tetikleyin.
Pages/Index.cshtml.cs:
public class IndexModel(
Service1 service1, Service2 service2, IService3 service3)
: PageModel
{
public void OnGet()
{
service1.Write("IndexModel.OnGet");
service2.Write("IndexModel.OnGet");
service3.Write("IndexModel.OnGet");
}
}
Hata ayıklama konsolu, Dizin sayfasının her yenilenmesinden sonra aşağıdaki çıkışı gösterir:
Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet, Key = Value from appsettings.Development.json
Service1.Dispose
Hizmet kapsayıcısı tarafından oluşturulmayan hizmetler
Aşağıdaki kodu inceleyin:
builder.Services.AddSingleton(new Service1());
builder.Services.AddSingleton(new Service2());
services.AddSingleton(new Service1());
services.AddSingleton(new Service2());
Önceki kod için:
- Hizmet örnekleri hizmet kapsayıcısı tarafından oluşturulmaz.
- Çerçeve, hizmetleri otomatik olarak sonlandırmıyor.
- Geliştirici, hizmetleri yok etme sorumluluğundadır.
IDisposable geçici ve paylaşılan örnekler için kılavuz
Daha fazla bilgi için bkz. .NET'te bağımlılık ekleme: Geçici ve paylaşılan örnek için IDisposable kılavuzu.
Varsayılan hizmet kapsayıcısının değiştirilmesi
Daha fazla bilgi için bkz. .NET'te bağımlılık ekleme: Varsayılan hizmet kapsayıcısı değiştirme.
Recommendations
Daha fazla bilgi için Bağımlılık ekleme yönergeleri: Öneriler bölümüne bakın.
Hizmet bulucu düzenini kullanmaktan kaçının. Örneğin, bunun yerine DI'yi kullanabileceğiniz bir hizmet örneğini almak için çağırmayın GetService :
Incorrect:
Correct:
public class MyClass(IOptionsMonitor<MyOptions> optionsMonitor)
{
public void MyMethod()
{
var option = optionsMonitor.CurrentValue.Option;
...
}
}
Kaçınılması gereken başka bir hizmet bulucu varyasyonu, çalışma zamanında bağımlılıkları çözümleyen bir fabrika eklemektir. Bu uygulamaların her ikisi de Inversion of Control stratejilerini bir araya getirebilir.
HttpContext öğesine statik olarak erişmekten kaçının (örneğin, IHttpContextAccessor.HttpContext).
DI, statik/genel nesne erişim desenlerine bir alternatiftir . Statik nesne erişimiyle karıştırırsanız DI'nin avantajlarını fark edemeyebilirsiniz.
Bağımlılık ilişkisi içinde çoklu kiracılık için önerilen desenler
Orchard Core , ASP.NET Core üzerinde modüler, çok kiracılı uygulamalar oluşturmaya yönelik bir uygulama çerçevesidir. Bkz. Orchard Core Belgeleri için daha fazla bilgi.
CMS'ye özgü özellikleri olmadan yalnızca Orchard Core Framework kullanarak modüler ve çok kiracılı uygulamalar oluşturma örnekleri için bkz . Orchard Core örnekleri.
Çerçeve tarafından sağlanan hizmetler
Dosya Program (.NET 6 veya üzeri) veya Startup dosyası (.NET 5 veya öncesi), uygulamanın kullandığı hizmetleri kaydeder; bunlar, Entity Framework Core gibi platform özellikleri ve Razor'deki bileşenleri Blazor (.NET 8 veya üzeri) destekleyen hizmetleri içerir. Başlangıçta, barındırıcı nasıl yapılandırıldıysa çerçeve tarafından tanımlanan hizmetlere IServiceCollection sahiptir. ASP.NET Core şablonlarına dayalı uygulamalar için çerçeve 250'den fazla hizmet kaydeder.
Aşağıdaki tabloda çerçeve kayıtlı hizmetlerin küçük bir örneği açıklanmaktadır:
| Hizmet türü | Lifetime |
|---|---|
| Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory | Transient |
| IHostApplicationLifetime | Singleton |
| IWebHostEnvironment | Singleton |
| Microsoft.AspNetCore.Hosting.IStartup | Singleton |
| Microsoft.AspNetCore.Hosting.IStartupFilter | Transient |
| Microsoft.AspNetCore.Hosting.Server.IServer | Singleton |
| Microsoft.AspNetCore.Http.IHttpContextFactory | Transient |
| Microsoft.Extensions.Logging.ILogger<TCategoryName> | Singleton |
| Microsoft.Extensions.Logging.ILoggerFactory | Singleton |
| Microsoft.Extensions.ObjectPool.ObjectPoolProvider | Singleton |
| Microsoft.Extensions.Options.IConfigureOptions<TOptions> | Transient |
| Microsoft.Extensions.Options.IOptions<TOptions> | Singleton |
| System.Diagnostics.DiagnosticSource | Singleton |
| System.Diagnostics.DiagnosticListener | Singleton |
Ek kaynaklar
- ASP.NET Core Blazor bağımlılık ekleme
- ASP.NET Core'daki görünümlere bağımlılık ekleme
- ASP.NET Core'daki denetleyicilere bağımlılık ekleme
- ASP.NET Core'da gereksinim işleyicilerine bağımlılık ekleme
- DI uygulaması geliştirme için NDC Konferans Desenleri
- ASP.NET Core'da uygulama başlatma
- ASP.NET Core'da fabrika tabanlı ara yazılım etkinleştirmesi
- .NET'te bağımlılık eklemeyle ilgili temel bilgileri anlama
- Bağımlılık enjeksiyonu yönergeleri
- Öğretici: .NET'te bağımlılık ekleme kullanma
- .NET bağımlılık ekleme
- ASP.NET Çekirdek Bağımlılık Ekleme: IServiceCollection nedir?
- IDisposables'ı ASP.NET Core'da atmanın dört yolu
- Bağımlılık Ekleme ile ASP.NET Core'da Temiz Kod Yazma (MSDN)
- Açık Bağımlılıklar İlkesi
- Denetim Kapsayıcılarının Ters Çevrilmesi ve Bağımlılık Ekleme Deseni (Martin Fowler)
- ASP.NET Core DI'de (Andrew Lock) birden çok arabirime sahip bir hizmeti kaydetme
- ASP.NET Core 3'te (Andrew Lock) Başlangıç hizmeti eklemeyi önleme
ASP.NET Core