ASP.NET Core bağımlılık ekleme
Kirk Larkabağı, Steve Smithve Brandon Dahler
ASP.NET Core, sınıflar ve bunların bağımlılıkları arasında denetimin ınversıon (ioc) elde etmek için bir teknik olan bağımlılık ekleme (dı) yazılım tasarım modelini destekler.
MVC denetleyicileri içindeki bağımlılık eklenmesine özgü daha fazla bilgi için bkz ASP.NET Core denetleyicilere bağımlılık ekleme ..
Web Apps dışındaki uygulamalarda bağımlılık ekleme hakkında daha fazla bilgi için bkz. .net 'e bağımlılık ekleme.
Seçeneklerin bağımlılığı ekleme hakkında daha fazla bilgi için bkz ASP.NET Core'da seçenek deseni ..
Bu konuda ASP.NET Core bağımlılık ekleme hakkında bilgi verilmektedir. Bağımlılık ekleme 'yi kullanmayla ilgili birincil belgeler, .net ' de bağımlılık ekleme' de yer alır.
Örnek kodu görüntüleme veya indirme (nasıl indirileceği)
Bağımlılık eklenmesine genel bakış
Bağımlılık , başka bir nesnenin bağımlı olduğu bir nesnedir. Aşağıdaki sınıfı, MyDependency WriteMessage diğer sınıfların bağımlı olduğu bir yöntemle inceleyin:
public class MyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
}
}
Bir sınıf, MyDependency yöntemini kullanmak için sınıfının bir örneğini oluşturabilir WriteMessage . Aşağıdaki örnekte, MyDependency sınıfı sınıfının bir bağımlılığı olur IndexModel :
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency();
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet");
}
}
Sınıfı oluşturur ve doğrudan MyDependency sınıfa bağlıdır. Önceki örnekte olduğu gibi kod bağımlılıkları sorunlu olur ve aşağıdaki nedenlerden dolayı kaçınılması gerekir:
MyDependencyFarklı bir uygulamayla değiştirmek için,IndexModelsınıfın değiştirilmesi gerekir.MyDependencyBağımlılıkları varsa, sınıf tarafından da yapılandırılmalıdırIndexModel. Uygulamasına bağlı olarak, birden çok sınıfı olan büyük bir projedeMyDependencyyapılandırma kodu uygulama genelinde dağılmış hale gelir.- Bu uygulamanın birim testi zordur.
Bağımlılık ekleme bu sorunları şu şekilde giderir:
- Bağımlılık uygulamasını soyutlamak için bir arabirim veya temel sınıf kullanımı.
- Bir hizmet kapsayıcısına bağımlılığın kaydı. ASP.NET Core, yerleşik bir hizmet kapsayıcısı sağlar IServiceProvider . Hizmetler genellikle uygulamanın program. cs dosyasına kaydedilir.
- Hizmetin kullanıldığı sınıf oluşturucusuna ekleme . Çerçeve, bağımlılığın bir örneğini oluşturma ve artık gerekli olmadığında bu uygulamayı atma sorumluluğunu alır.
Örnek uygulamada, IMyDependency arabirimi WriteMessage yöntemini tanımlar:
public interface IMyDependency
{
void WriteMessage(string message);
}
Bu arabirim somut bir tür tarafından uygulanır, MyDependency :
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
Örnek uygulama, IMyDependency hizmeti somut tür ile kaydeder MyDependency . AddScopedYöntemi, hizmeti tek bir isteğin ömrü olan kapsamlı bir yaşam süresine kaydeder. Hizmet yaşam süreleri bu konunun ilerleyen kısımlarında açıklanmıştır.
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency>();
var app = builder.Build();
Örnek uygulamada, IMyDependency hizmet istenir ve yöntemi çağırmak için kullanılır WriteMessage :
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency;
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void OnGet()
{
_myDependency.WriteMessage("Index2Model.OnGet");
}
}
DI modelini, denetleyiciyi veya Razor sayfasını kullanarak:
- Somut türü kullanmaz
MyDependency, yalnızcaIMyDependencyuyguladığı arabirim. Bu, denetleyiciyi veya sayfayı değiştirmeden uygulamanın değiştirilmesini kolaylaştırır Razor . - Bir örneği oluşturmaz
MyDependency, bu, dı kapsayıcısı tarafından oluşturulur.
Arabirim uygulanması, IMyDependency yerleşik günlük API 'si kullanılarak artırılabilir:
public class MyDependency2 : IMyDependency
{
private readonly ILogger<MyDependency2> _logger;
public MyDependency2(ILogger<MyDependency2> logger)
{
_logger = logger;
}
public void WriteMessage(string message)
{
_logger.LogInformation( $"MyDependency2.WriteMessage Message: {message}");
}
}
Güncelleştirilmiş program. cs yeni IMyDependency uygulamayı kaydeder:
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency2>();
var app = builder.Build();
MyDependency2ILogger<TCategoryName>, oluşturucuda istediği öğesine bağlıdır. ILogger<TCategoryName>Framework tarafından sağlanmış bir hizmettir.
Bağımlılık ekleme işlemini zincirleme bir biçimde kullanmak olağan dışı değildir. Her istenen bağımlılık, kendi bağımlılıklarını ister. Kapsayıcı grafikteki bağımlılıkları çözer ve tamamen çözümlenen hizmeti döndürür. Çözümlenmesi gereken, genellikle bağımlılık ağacı, bağımlılık grafiği veya nesne grafiği olarak adlandırılan toplu bağımlılıklar kümesi.
Kapsayıcı, ILogger<TCategoryName> (genel) açık türlerdenyararlanarak çözümlenir, her (genel) oluşturulan türükaydetme ihtiyacını ortadan kaldırır.
Bağımlılık ekleme terminolojisi ' nde bir hizmet:
- Genellikle hizmet gibi diğer nesnelere hizmet sağlayan bir nesnedir
IMyDependency. - Bir Web hizmetiyle ilgili değildir, ancak hizmet bir Web hizmeti kullanabilir.
Çerçeve, güçlü bir günlük sistemi sağlar. IMyDependencyYukarıdaki örneklerde gösterilen uygulamalar, günlüğü uygulamamak için değil temel dı 'yi göstermek için yazılmıştır. Çoğu uygulamanın Günlükçüler yazması gerekmez. Aşağıdaki kod, hiçbir hizmetin kaydedilmesini gerektirmeyen varsayılan günlük kaydını kullanmayı gösterir:
public class AboutModel : PageModel
{
private readonly ILogger _logger;
public AboutModel(ILogger<AboutModel> logger)
{
_logger = logger;
}
public string Message { get; set; } = string.Empty;
public void OnGet()
{
Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
_logger.LogInformation(Message);
}
}
Önceki kodu kullanarak, Framework tarafından günlüğe kaydetme sağlandığı için program. cs' yi güncelleştirmeniz gerekmez.
Program. c dosyasına eklenen hizmetler
Dı kapsayıcısına kayıtlı tüm hizmetler, app.Services program. cs içinden çözülebilir:
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency>();
var app = builder.Build();
Uzantı yöntemleriyle hizmet gruplarını kaydet
ASP.NET Core framework, bir grup ilgili hizmeti kaydetmek için bir kural kullanır. Kural, Add{GROUP_NAME} bir Framework özelliği için gereken tüm hizmetleri kaydetmek için tek bir genişletme yöntemi kullanmaktır. Örneğin, AddControllers genişletme YÖNTEMI MVC denetleyicileri için gereken hizmetleri kaydeder.
Aşağıdaki kod, Razor bireysel kullanıcı hesapları kullanılarak sayfalar şablonu tarafından oluşturulur ve uzantı yöntemlerini kullanarak kapsayıcıya ek hizmetler eklemeyi gösterir AddDbContext ve AddDefaultIdentity :
using DependencyInjectionSample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
var app = builder.Build();
Hizmetleri kaydeden ve seçenekleri yapılandıran aşağıdakileri göz önünde bulundurun:
using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
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>();
var app = builder.Build();
İlgili kayıt grupları, Hizmetleri kaydetmek için bir genişletme yöntemine taşınabilir. Örneğin, Yapılandırma Hizmetleri aşağıdaki sınıfa eklenir:
using ConfigSample.Options;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MyConfigServiceCollectionExtensions
{
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;
}
}
}
Kalan hizmetler benzer bir sınıfa kaydedilir. Aşağıdaki kod, Hizmetleri kaydetmek için yeni genişletme yöntemlerini kullanır:
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddConfig(builder.Configuration)
.AddMyDependencyGroup();
builder.Services.AddRazorPages();
var app = builder.Build();
Note: Her services.Add{GROUP_NAME} uzantı yöntemi, Hizmetleri ekler ve potansiyel olarak yapılandırır. Örneğin, AddControllersWithViews görünümler için gereken HIZMETLERI MVC denetleyicileri ekler ve AddRazorPages hizmet Razor sayfalarını ekler. Uygulamaların ad alanında uzantı yöntemleri oluşturma adlandırma kuralını izlemesini öneririz Microsoft.Extensions.DependencyInjection . Ad alanında uzantı yöntemleri oluşturma Microsoft.Extensions.DependencyInjection :
- Hizmet kaydı gruplarını kapsüller.
- Hizmete uygun IntelliSense erişimi sağlar.
Hizmet yaşam süreleri
Bkz. .net 'Te bağımlılık ekleme içindeki hizmet yaşam süreleri
Ara yazılım kapsamındaki hizmetleri kullanmak için aşağıdaki yaklaşımlardan birini kullanın:
- Hizmeti, ara yazılımı
InvokeveyaInvokeAsyncyöntemine ekleyin. Oluşturucu Ekleme kullanılması, kapsamlı hizmeti tek bir gibi davranmaya zordığı için bir çalışma zamanı özel durumu oluşturur. Ömür ve kayıt seçenekleri bölümündeki örnek,InvokeAsyncyaklaşımı gösterir. - Fabrika tabanlı ara yazılımkullanın. Bu yaklaşım kullanılarak kaydedilen ara yazılım, kapsamlı hizmetlerin ara yazılım yöntemine eklenmiş olmasına olanak tanıyan istemci isteği (bağlantı) başına etkinleştirilir
InvokeAsync.
Daha fazla bilgi için bkz. özel ASP.NET Core ara yazılımı yaz.
Hizmet kayıt yöntemleri
.Net ' te bağımlılık ekleme içindeki hizmet kayıt yöntemlerine bakın
Test için izleme türleriolduğunda birden çok uygulama kullanılması yaygındır.
Hizmeti yalnızca bir uygulama türüyle kaydetmek, bu hizmeti aynı uygulama ve hizmet türüyle kaydetmeye eşdeğerdir. Bu, bir hizmetin birden çok uygulamasının açık bir hizmet türü kullanmayan yöntemler kullanılarak kaydedilamamasının nedenleridir. Bu yöntemler bir hizmetin birden fazla örneğini kaydedebilir, ancak hepsi aynı uygulama türüne sahip olur.
Yukarıdaki hizmet kayıt yöntemlerinden herhangi biri aynı hizmet türünün birden çok hizmet örneğini kaydetmek için kullanılabilir. Aşağıdaki örnekte, AddSingleton hizmet türü olarak ile iki kez çağırılır IMyDependency . İçin ikinci çağrı, AddSingleton olarak çözümlendikten önceki bir öncekini geçersiz kılar IMyDependency ve aracılığıyla birden çok hizmet çözümlendiğinde bir öncekini ekler IEnumerable<IMyDependency> . Hizmetler, ile çözümlendiklerinde kaydedildikleri sırada görüntülenir IEnumerable<{SERVICE}> .
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);
}
}
Oluşturucu Ekleme davranışı
.Net ' te bağımlılık ekleme bölümüne bkz. Oluşturucu Ekleme davranışı
Entity Framework bağlamları
Varsayılan olarak, Web uygulaması veritabanı işlemleri normalde istemci isteği kapsamında olduğundan, Entity Framework bağlamları kapsama yaşam süresi kullanılarak hizmet kapsayıcısına eklenir. Farklı bir yaşam süresi kullanmak için, bir aşırı yükleme kullanarak yaşam süresini belirtin AddDbContext . Belirli bir yaşam süresinin Hizmetleri, hizmetin yaşam süresinden kısa olan bir yaşam süresine sahip bir veritabanı bağlamı kullanmamalıdır.
Ömür ve kayıt seçenekleri
Hizmet yaşam süreleri ve kayıt seçenekleri arasındaki farkı göstermek için, bir görevi tanımlayıcı ile bir işlem olarak temsil eden aşağıdaki arayüzleri göz önünde bulundurun OperationId . Bir işlemin hizmetinin yaşam süresinin 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ı ya da farklı örneklerini sağlar:
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 arabirimlerin tümünü uygular. OperationOluşturucu BIR GUID oluşturur ve son 4 karakteri OperationId özellikte depolar:
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
public Operation()
{
OperationId = Guid.NewGuid().ToString()[^4..];
}
public string OperationId { get; }
}
Aşağıdaki kod, Operation adlandırılmış yaşam sürelerine göre sınıfının birden çok kaydı oluşturur:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddTransient<IOperationTransient, Operation>();
builder.Services.AddScoped<IOperationScoped, Operation>();
builder.Services.AddSingleton<IOperationSingleton, Operation>();
var app = builder.Build();
Örnek uygulama, isteklerin içindeki ve içindeki nesne yaşam sürelerini gösterir. IndexModelVe ara yazılım her IOperation tür türü ister, OperationId her biri için günlük kaydı:
public class IndexModel : PageModel
{
private readonly ILogger _logger;
private readonly IOperationTransient _transientOperation;
private readonly IOperationSingleton _singletonOperation;
private readonly IOperationScoped _scopedOperation;
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);
}
}
Uygulamasına benzer şekilde, IndexModel Ara yazılım aynı hizmetleri çözümler:
public class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly IOperationTransient _transientOperation;
private readonly IOperationSingleton _singletonOperation;
public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger,
IOperationTransient transientOperation,
IOperationSingleton singletonOperation)
{
_logger = logger;
_transientOperation = transientOperation;
_singletonOperation = singletonOperation;
_next = next;
}
public async Task InvokeAsync(HttpContext context,
IOperationScoped scopedOperation)
{
_logger.LogInformation("Transient: " + _transientOperation.OperationId);
_logger.LogInformation("Scoped: " + scopedOperation.OperationId);
_logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
await _next(context);
}
}
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
Kapsamındaki hizmetlerin yöntemde çözülmesi gerekir InvokeAsync :
public async Task InvokeAsync(HttpContext context,
IOperationScoped scopedOperation)
{
_logger.LogInformation("Transient: " + _transientOperation.OperationId);
_logger.LogInformation("Scoped: " + scopedOperation.OperationId);
_logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
await _next(context);
}
Günlükçü çıktısı şunu gösterir:
- Geçici nesneler her zaman farklıdır. Geçici
OperationIddeğer, ara yazılımdakiIndexModelve içinde farklıdır. - Kapsamlı nesneler, verilen bir istek için aynıdır, ancak her yeni istekte farklılık gösterir.
- Tek nesne nesneleri her istek için aynıdır.
Günlük çıkışını azaltmak için uygulama ayarları içinde "Logging:LogLevel:Microsoft:Error" değerini ayarlayın. Development.json dosyası:
{
"MyKey": "MyKey from appsettings.Developement.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Debug",
"Microsoft": "Error"
}
}
}
Uygulama başlatmada bir hizmeti çözümleme
Aşağıdaki kodda, uygulama başlatıldığında sınırlı bir süre boyunca kapsamı belirli bir hizmetin nasıl çözümlen olduğu gösterir:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IMyDependency, MyDependency>();
var app = builder.Build();
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var myDependency = services.GetRequiredService<IMyDependency>();
myDependency.WriteMessage("Call services from main");
}
app.MapGet("/", () => "Hello World!");
app.Run();
Kapsam doğrulaması
Bkz. .NET'te bağımlılık eklemede oluşturucu ekleme davranışı
Daha fazla bilgi için bkz. Kapsam doğrulaması.
İstek Hizmetleri
Bir istek içindeki hizmetler ve bağımlılıkları ASP.NET Core aracılığıyla ortaya HttpContext.RequestServices çıkar.
Çerçeve, istek başına bir kapsam oluşturur RequestServices ve kapsamlı hizmet sağlayıcısını gösterir. tüm kapsamlı hizmetler, istek etkin olduğu sürece geçerlidir.
Not
bağımlılıklarını, 'den hizmetleri çözümlemek yerine oluşturucu parametreleri olarak istekte bulundurmayı tercih RequestServices eder. Bağımlılıkları oluşturucu parametreleri olarak talep etmek, test etmek daha kolay sınıflar oluşturur.
Bağımlılık ekleme için hizmetleri tasarlama
Bağımlılık ekleme için hizmetler tasarlarken:
- Durum bilgisine, statik sınıflara ve üyelere karşı kaçının. Uygulamaları bunun yerine tekli hizmetleri kullanmak üzere tasararak genel durum oluşturmaktan kaçının.
- Hizmetler içindeki bağımlı sınıfların doğrudan örneğini esnleme. Doğrudan örnekleme, kodu belirli bir uygulamaya yönlendirmektedir.
- Hizmetleri küçük, iyi faktörlü ve kolayca test edilmiş hale.
Bir sınıfta çok fazla bağımlılık varsa, sınıfın çok fazla sorumluluğu olduğunu ve Tek Sorumluluk İlkesini (SRP)ihlal ettiğinin bir işareti olabilir. Bazı sorumluluklarını yeni sınıflara dönüştürerek sınıfı yeniden düzenlemeyi deneme. Sayfalar sayfa modeli Razor sınıfları ve MVC denetleyici sınıflarında kullanıcı arabirimi endişelerini dikkate almaları gerektiğini unutmayın.
Hizmetlerin atılması
Kapsayıcı, Dispose oluşturduğu türleri IDisposable arar. Kapsayıcıdan çözümlenen hizmetler hiçbir zaman geliştirici tarafından atılması gerekir. Bir tür veya fabrika tekton olarak kaydedilirse, kapsayıcı singleton'ı otomatik olarak atacaktır.
Aşağıdaki örnekte hizmetler hizmet kapsayıcısı tarafından oluşturulur ve otomatik olarak atılır: dependency-injection\samples\6.x\DIsample2\Services\Service1.cs [!code-csharp]
using DIsample2.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<Service1>();
builder.Services.AddSingleton<Service2>();
var myKey = builder.Configuration["MyKey"];
builder.Services.AddSingleton<IService3>(sp => new Service3(myKey));
var app = builder.Build();
public class IndexModel : PageModel
{
private readonly Service1 _service1;
private readonly Service2 _service2;
private readonly IService3 _service3;
public IndexModel(Service1 service1, Service2 service2, IService3 service3)
{
_service1 = service1;
_service2 = service2;
_service3 = service3;
}
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
Service1.Dispose
Hizmet kapsayıcısı tarafından oluşturulmaz hizmetler
Aşağıdaki kodu inceleyin:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSingleton<Service1>();
builder.Services.AddSingleton<Service2>();
Yukarıdaki kodda:
- Hizmet örnekleri hizmet kapsayıcısı tarafından oluşturulmaz.
- Çerçeve hizmetleri otomatik olarak atmaz.
- Hizmetlerden sorumlu geliştiricidir.
Geçici ve paylaşılan örnekler için IDisposable kılavuzu
.NET'te bağımlılık ekleme konusunda Geçici ve paylaşılan örnek için IDisposable kılavuzuna bakın
Varsayılan hizmet kapsayıcısı değiştirme
Bkz. .NET'te bağımlılık eklemede varsayılan hizmet kapsayıcısı değiştirme
Öneriler
.NET Öneriler bağımlılık ekleme içinde bkz.
Hizmet bulucu desenini kullanmaktan kaçının. Örneğin, bunun yerine GetService DI'ı kullanabileceğiniz durumlarda bir hizmet örneği almak için çağırmayın:
Yanlış:

Doğru:
public class MyClass { private readonly IOptionsMonitor<MyOptions> _optionsMonitor; public MyClass(IOptionsMonitor<MyOptions> optionsMonitor) { _optionsMonitor = optionsMonitor; } public void MyMethod() { var option = _optionsMonitor.CurrentValue.Option; ... } }Kaçınılması gereken bir diğer hizmet bulucu varyasyonu da çalışma zamanında bağımlılıkları çözümleten bir fabrikayı eklemedir. Bu yöntemlerin ikisi de Denetim Stratejilerinin Ters Çevirmesi'nin karışımını sağlar.
için statik
HttpContexterişimden kaçının (örneğin, IHttpContextAccessor.HttpContext).
DI, statik/genel nesne erişim desenlerine alternatiftir. Statik nesne erişimiyle karıştırarak DI'nin avantajlarını fark edeyeyemebilirsiniz.
DI'de çok katmanlılık için önerilen desenler
Core, bulut üzerinde modüler, çok kiracılı uygulamalar için bir uygulama ASP.NET Core. Daha fazla bilgi için, Bkz. Temel Belgeler.
CMS'ye özgü özellikleri olmadan yalnızca Core Framework'leri kullanarak modüler ve çok kiracılı uygulamalar derleme örnekleri için Bkz. Temel Çekirdek örnekleri.
Çerçeve tarafından sağlanan hizmetler
Program.cs, Entity Framework Core ve ASP.NET Core MVC gibi platform özellikleri de dahil olmak üzere uygulamanın kullandığı ASP.NET Core kaydedmektedir. Başlangıçta, IServiceCollection Program.cs'ye sağlanan hizmetlerde, ana bilgisayarının nasıl yapılandırlandığına bağlı olarak çerçeve tarafından tanımlanan hizmetler vardır. Çerçeve, uygulama şablonlarına ASP.NET Core uygulamalar için 250'den fazla hizmeti kaydettirmektedir.
Aşağıdaki tabloda bu çerçeve kayıtlı hizmetlerin küçük bir örneği listelemektedir:
| Hizmet Türü | Ömür |
|---|---|
| Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory | Geçi -ci |
| IHostApplicationLifetime | Singleton |
| IWebHostEnvironment | Singleton |
| Microsoft.AspNetCore.Hosting.IStartup | Singleton |
| Microsoft.AspNetCore.Hosting.IStartupFilter | Geçi -ci |
| Microsoft.AspNetCore.Hosting.Server.IServer | Singleton |
| Microsoft.AspNetCore.Http.IHttpContextFactory | Geçi -ci |
| Microsoft.Extensions.Logging.ILogger<TCategoryName> | Singleton |
| Microsoft.Extensions.Logging.ILoggerFactory | Singleton |
| Microsoft.Extensions.ObjectPool.ObjectPoolProvider | Singleton |
| Microsoft.Extensions.Options.IConfigureOptions<TOptions> | Geçi -ci |
| Microsoft.Extensions.Options.IOptions<TOptions> | Singleton |
| System.Diagnostics.DiagnosticSource | Singleton |
| System.Diagnostics.DiagnosticListener | Singleton |
Ek kaynaklar
- ASP.NET Core görünümlere bağımlılık ekleme
- ASP.NET Core denetleyicilere bağımlılık ekleme
- ASP.NET Core'de gereksinim işleyicilere bağımlılık ekleme
- ASP.NET Core Blazor bağımlılık ekleme
- DI uygulaması geliştirme için NDC Konferans Desenleri
- ASP.NET Core 'de uygulama başlatma
- ASP.NET Core 'de fabrika tabanlı ara yazılım etkinleştirmesi
- IDisposables'ın ASP.NET Core
- Bağımlılık Ekleme ile ASP.NET Core Kodu Yazma (MSDN)
- Açık Bağımlılıklar İlkesi
- Denetim Kapsayıcılarının ve Bağımlılık Ekleme Deseninin TersIni (Martin Fowler)
- ASP.NET CORE DI'de birden çok arabirime sahip bir ASP.NET Core kaydetme
Scott Larkin, Steve Smith, Scott Addieve Scott Dahler
ASP.NET Core, sınıflar ve bağımlılıkları arasında Denetimin Ters Çevirmesi (IoC) elde etmek için kullanılan bir teknik olan bağımlılık ekleme (DI) yazılım tasarım desenini destekler.
MVC denetleyicilerinde bağımlılık eklemeye özgü daha fazla bilgi için bkz. ASP.NET Core denetleyicilere bağımlılık ekleme .
Web uygulamaları dışında uygulamalarda bağımlılık ekleme kullanma hakkında bilgi için bkz. .NET'te bağımlılık ekleme.
Seçeneklerin bağımlılık eklemesi hakkında daha fazla bilgi için bkz. ASP.NET Core'da seçenek deseni .
Bu konuda, uygulama içinde bağımlılık ekleme hakkında ASP.NET Core. Bağımlılık ekleme kullanmayla ilgili birincil belgeler .NET'te Bağımlılık ekleme içinde yer alan belgelerdir.
Örnek kodu görüntüleme veya indirme ( nasılindir)
Bağımlılık eklemeye genel bakış
Bağımlılık, başka bir nesnenin bağımlı olduğu bir nesnedir. Aşağıdaki MyDependency sınıfı, diğer WriteMessage sınıfların bağımlı olduğu bir yöntemle inceler:
public class MyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
}
}
Bir sınıf, yöntemini kullanmak MyDependency için sınıfının bir örneğini WriteMessage oluşturabilir. Aşağıdaki örnekte, MyDependency sınıfı sınıfının bir IndexModel bağımlılığıdır:
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency();
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet created this message.");
}
}
sınıfı oluşturur ve doğrudan sınıfına MyDependency bağlıdır. Önceki örnekte olduğu gibi kod bağımlılıkları sorunludur ve aşağıdaki nedenlerle kaçınılmalıdır:
MyDependencyFarklı bir uygulamayla değiştirmek için,IndexModelsınıfın değiştirilmesi gerekir.MyDependencyBağımlılıkları varsa, sınıf tarafından da yapılandırılmalıdırIndexModel. Uygulamasına bağlı olarak, birden çok sınıfı olan büyük bir projedeMyDependencyyapılandırma kodu uygulama genelinde dağılmış hale gelir.- Bu uygulamanın birim testi zordur. Uygulamanın
MyDependencyBu yaklaşım ile mümkün olmayan bir sahte veya saplama sınıfı kullanması gerekir.
Bağımlılık ekleme bu sorunları şu şekilde giderir:
- Bağımlılık uygulamasını soyutlamak için bir arabirim veya temel sınıf kullanımı.
- Bir hizmet kapsayıcısına bağımlılığın kaydı. ASP.NET Core, yerleşik bir hizmet kapsayıcısı sağlar IServiceProvider . Hizmetler genellikle uygulamanın
Startup.ConfigureServicesyöntemine kaydedilir. - Hizmetin kullanıldığı sınıf oluşturucusuna ekleme . Çerçeve, bağımlılığın bir örneğini oluşturma ve artık gerekli olmadığında bu uygulamayı atma sorumluluğunu alır.
Örnek uygulamada, IMyDependency arabirimi WriteMessage yöntemini tanımlar:
public interface IMyDependency
{
void WriteMessage(string message);
}
Bu arabirim somut bir tür tarafından uygulanır, MyDependency :
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
Örnek uygulama, IMyDependency hizmeti somut tür ile kaydeder MyDependency . AddScopedYöntemi, hizmeti tek bir isteğin ömrü olan kapsamlı bir yaşam süresine kaydeder. Hizmet yaşam süreleri bu konunun ilerleyen kısımlarında açıklanmıştır.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddRazorPages();
}
Örnek uygulamada, IMyDependency hizmet istenir ve yöntemi çağırmak için kullanılır WriteMessage :
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency;
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void OnGet()
{
_myDependency.WriteMessage("Index2Model.OnGet");
}
}
DI modelini kullanarak denetleyici:
- Somut türü kullanmaz
MyDependency, yalnızcaIMyDependencyuyguladığı arabirim. Bu, denetleyicinin, denetleyiciyi değiştirmeden kullandığı uygulamayı değiştirmeyi kolaylaştırır. - Bir örneği oluşturmaz
MyDependency, bu, dı kapsayıcısı tarafından oluşturulur.
Arabirim uygulanması, IMyDependency yerleşik günlük API 'si kullanılarak artırılabilir:
public class MyDependency2 : IMyDependency
{
private readonly ILogger<MyDependency2> _logger;
public MyDependency2(ILogger<MyDependency2> logger)
{
_logger = logger;
}
public void WriteMessage(string message)
{
_logger.LogInformation( $"MyDependency2.WriteMessage Message: {message}");
}
}
Updated ConfigureServices yöntemi yeni IMyDependency uygulamayı kaydeder:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency2>();
services.AddRazorPages();
}
MyDependency2ILogger<TCategoryName>, oluşturucuda istediği öğesine bağlıdır. ILogger<TCategoryName>Framework tarafından sağlanmış bir hizmettir.
Bağımlılık ekleme işlemini zincirleme bir biçimde kullanmak olağan dışı değildir. Her istenen bağımlılık, kendi bağımlılıklarını ister. Kapsayıcı grafikteki bağımlılıkları çözer ve tamamen çözümlenen hizmeti döndürür. Çözümlenmesi gereken, genellikle bağımlılık ağacı, bağımlılık grafiği veya nesne grafiği olarak adlandırılan toplu bağımlılıklar kümesi.
Kapsayıcı, ILogger<TCategoryName> (genel) açık türlerdenyararlanarak çözümlenir, her (genel) oluşturulan türükaydetme ihtiyacını ortadan kaldırır.
Bağımlılık ekleme terminolojisi ' nde bir hizmet:
- Genellikle hizmet gibi diğer nesnelere hizmet sağlayan bir nesnedir
IMyDependency. - Bir Web hizmetiyle ilgili değildir, ancak hizmet bir Web hizmeti kullanabilir.
Çerçeve, güçlü bir günlük sistemi sağlar. IMyDependencyYukarıdaki örneklerde gösterilen uygulamalar, günlüğü uygulamamak için değil temel dı 'yi göstermek için yazılmıştır. Çoğu uygulamanın Günlükçüler yazması gerekmez. Aşağıdaki kod, bir hizmetin kaydedilmesini gerektirmeyen varsayılan günlük kaydını kullanmayı göstermektedir ConfigureServices :
public class AboutModel : PageModel
{
private readonly ILogger _logger;
public AboutModel(ILogger<AboutModel> logger)
{
_logger = logger;
}
public string Message { get; set; }
public void OnGet()
{
Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
_logger.LogInformation(Message);
}
}
Yukarıdaki kodu kullanarak, ConfigureServices Framework tarafından günlüğe kaydetme sağlandığı için güncelleştirmeniz gerekmez.
Başlangıca eklenen hizmetler
Hizmetler Startup oluşturucuya ve Startup.Configure metoduna eklenebilir.
StartupGenel ana bilgisayar () kullanılırken oluşturucuya yalnızca aşağıdaki hizmetler eklenebilir IHostBuilder :
Dı kapsayıcısına kayıtlı tüm hizmetler Startup.Configure metoduna eklenebilir:
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
...
}
Daha fazla bilgi için, bkz ASP.NET Core 'de uygulama başlatma . ve erişim yapılandırması başlangıç.
Uzantı yöntemleriyle hizmet gruplarını kaydet
ASP.NET Core framework, bir grup ilgili hizmeti kaydetmek için bir kural kullanır. Kural, Add{GROUP_NAME} bir Framework özelliği için gereken tüm hizmetleri kaydetmek için tek bir genişletme yöntemi kullanmaktır. Örneğin, AddControllers genişletme YÖNTEMI MVC denetleyicileri için gereken hizmetleri kaydeder.
Aşağıdaki kod, Razor bireysel kullanıcı hesapları kullanılarak sayfalar şablonu tarafından oluşturulur ve uzantı yöntemlerini kullanarak kapsayıcıya ek hizmetler eklemeyi gösterir AddDbContext ve AddDefaultIdentity :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
}
ConfigureServicesHizmetleri kaydeden ve seçenekleri yapılandıran aşağıdaki yöntemi göz önünde bulundurun:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(
Configuration.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>(
Configuration.GetSection(ColorOptions.Color));
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
services.AddRazorPages();
}
İlgili kayıt grupları, Hizmetleri kaydetmek için bir genişletme yöntemine taşınabilir. Örneğin, Yapılandırma Hizmetleri aşağıdaki sınıfa eklenir:
using ConfigSample.Options;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MyConfigServiceCollectionExtensions
{
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;
}
}
}
Kalan hizmetler benzer bir sınıfa kaydedilir. Aşağıdaki ConfigureServices Yöntem, Hizmetleri kaydetmek için yeni genişletme yöntemlerini kullanır:
public void ConfigureServices(IServiceCollection services)
{
services.AddConfig(Configuration)
.AddMyDependencyGroup();
services.AddRazorPages();
}
Note: Her services.Add{GROUP_NAME} uzantı yöntemi, Hizmetleri ekler ve potansiyel olarak yapılandırır. Örneğin, AddControllersWithViews görünümler için gereken HIZMETLERI MVC denetleyicileri ekler ve AddRazorPages hizmet Razor sayfalarını ekler. Uygulamaların ad alanında uzantı yöntemleri oluşturma adlandırma kuralını izlemesini öneririz Microsoft.Extensions.DependencyInjection . Ad alanında uzantı yöntemleri oluşturma Microsoft.Extensions.DependencyInjection :
- Hizmet kaydı gruplarını kapsüller.
- Hizmete uygun IntelliSense erişimi sağlar.
Hizmet yaşam süreleri
Bkz. .net 'Te bağımlılık ekleme içindeki hizmet yaşam süreleri
Ara yazılım kapsamındaki hizmetleri kullanmak için aşağıdaki yaklaşımlardan birini kullanın:
- Hizmeti, ara yazılımı
InvokeveyaInvokeAsyncyöntemine ekleyin. Oluşturucu Ekleme kullanılması, kapsamlı hizmeti tek bir gibi davranmaya zordığı için bir çalışma zamanı özel durumu oluşturur. Ömür ve kayıt seçenekleri bölümündeki örnek,InvokeAsyncyaklaşımı gösterir. - Fabrika tabanlı ara yazılımkullanın. Bu yaklaşım kullanılarak kaydedilen ara yazılım, kapsamlı hizmetlerin ara yazılım yöntemine eklenmiş olmasına olanak tanıyan istemci isteği (bağlantı) başına etkinleştirilir
InvokeAsync.
Daha fazla bilgi için bkz. özel ASP.NET Core ara yazılımı yaz.
Hizmet kayıt yöntemleri
.Net ' te bağımlılık ekleme içindeki hizmet kayıt yöntemlerine bakın
Test için izleme türleriolduğunda birden çok uygulama kullanılması yaygındır.
Hizmeti yalnızca bir uygulama türüyle kaydetmek, bu hizmeti aynı uygulama ve hizmet türüyle kaydetmeye eşdeğerdir. Bu, bir hizmetin birden çok uygulamasının açık bir hizmet türü kullanmayan yöntemler kullanılarak kaydedilamamasının nedenleridir. Bu yöntemler bir hizmetin birden fazla örneğini kaydedebilir, ancak hepsi aynı uygulama türüne sahip olur.
Yukarıdaki hizmet kayıt yöntemlerinden herhangi biri aynı hizmet türünün birden çok hizmet örneğini kaydetmek için kullanılabilir. Aşağıdaki örnekte, AddSingleton hizmet türü olarak ile iki kez çağırılır IMyDependency . İçin ikinci çağrı, AddSingleton olarak çözümlendikten önceki bir öncekini geçersiz kılar IMyDependency ve aracılığıyla birden çok hizmet çözümlendiğinde bir öncekini ekler IEnumerable<IMyDependency> . Hizmetler, ile çözümlendiklerinde kaydedildikleri sırada görüntülenir IEnumerable<{SERVICE}> .
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);
}
}
Oluşturucu Ekleme davranışı
.Net ' te bağımlılık ekleme bölümüne bkz. Oluşturucu Ekleme davranışı
Entity Framework bağlamları
Varsayılan olarak, Web uygulaması veritabanı işlemleri normalde istemci isteği kapsamında olduğundan, Entity Framework bağlamları kapsama yaşam süresi kullanılarak hizmet kapsayıcısına eklenir. Farklı bir yaşam süresi kullanmak için, bir aşırı yükleme kullanarak yaşam süresini belirtin AddDbContext . Belirli bir yaşam süresinin Hizmetleri, hizmetin yaşam süresinden kısa olan bir yaşam süresine sahip bir veritabanı bağlamı kullanmamalıdır.
Ömür ve kayıt seçenekleri
Hizmet yaşam süreleri ve kayıt seçenekleri arasındaki farkı göstermek için, bir görevi tanımlayıcı ile bir işlem olarak temsil eden aşağıdaki arayüzleri göz önünde bulundurun OperationId . Bir işlemin hizmetinin yaşam süresinin 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ı ya da farklı örneklerini sağlar:
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 arabirimlerin tümünü uygular. OperationOluşturucu BIR GUID oluşturur ve son 4 karakteri OperationId özellikte depolar:
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
public Operation()
{
OperationId = Guid.NewGuid().ToString()[^4..];
}
public string OperationId { get; }
}
Startup.ConfigureServicesYöntemi, Operation adlandırılmış yaşam sürelerine göre sınıfının birden çok kaydı oluşturur:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddRazorPages();
}
Örnek uygulama, isteklerin içindeki ve içindeki nesne yaşam sürelerini gösterir. IndexModelVe ara yazılım her IOperation tür türü ister, OperationId her biri için günlük kaydı:
public class IndexModel : PageModel
{
private readonly ILogger _logger;
private readonly IOperationTransient _transientOperation;
private readonly IOperationSingleton _singletonOperation;
private readonly IOperationScoped _scopedOperation;
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);
}
}
Uygulamasına benzer şekilde, IndexModel Ara yazılım aynı hizmetleri çözümler:
public class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly IOperationTransient _transientOperation;
private readonly IOperationSingleton _singletonOperation;
public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger,
IOperationTransient transientOperation,
IOperationSingleton singletonOperation)
{
_logger = logger;
_transientOperation = transientOperation;
_singletonOperation = singletonOperation;
_next = next;
}
public async Task InvokeAsync(HttpContext context,
IOperationScoped scopedOperation)
{
_logger.LogInformation("Transient: " + _transientOperation.OperationId);
_logger.LogInformation("Scoped: " + scopedOperation.OperationId);
_logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
await _next(context);
}
}
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
Kapsamındaki hizmetlerin yöntemde çözülmesi gerekir InvokeAsync :
public async Task InvokeAsync(HttpContext context,
IOperationScoped scopedOperation)
{
_logger.LogInformation("Transient: " + _transientOperation.OperationId);
_logger.LogInformation("Scoped: " + scopedOperation.OperationId);
_logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
await _next(context);
}
Günlükçü çıktısı şunu gösterir:
- Geçici nesneler her zaman farklıdır. Geçici
OperationIddeğer,IndexModelAra yazılım içindeki ve içinde farklıdır. - Kapsamlı nesneler, belirli bir istek için aynıdır ancak her yeni istek arasında farklılık gösterir.
- Tek nesneler her istek için aynıdır.
Günlüğe kaydetme çıkışını azaltmak için appSettings 'de "Logging: LogLevel: Microsoft: Error" seçeneğini ayarlayın . Development. JSON dosyası:
{
"MyKey": "MyKey from appsettings.Developement.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Debug",
"Microsoft": "Error"
}
}
}
Ana bilgisayardan Hizmetleri çağır
IServiceScopeUygulamanın kapsamındaki bir kapsamlı hizmeti çözümlemek Için ıvicescopefactory. CreateScope ile bir oluşturun. Bu yaklaşım, başlatma görevlerini çalıştırmak üzere başlangıçta kapsamlı bir hizmete erişmek için yararlıdır.
Aşağıdaki örnek, kapsamındaki hizmete nasıl erişeceğinden IMyDependency ve yönteminin içinde nasıl çağrılacağını göstermektedir WriteMessage Program.Main :
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
try
{
var myDependency = services.GetRequiredService<IMyDependency>();
myDependency.WriteMessage("Call services from main");
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Kapsam doğrulaması
.Net ' te bağımlılık ekleme bölümüne bkz. Oluşturucu Ekleme davranışı
Daha fazla bilgi için bkz. kapsam doğrulaması.
İstek Hizmetleri
bir ASP.NET Core isteği içindeki hizmetler ve bağımlılıklar aracılığıyla sunulur HttpContext.RequestServices .
Çerçeve, istek başına bir kapsam oluşturur ve RequestServices kapsamlı hizmet sağlayıcısını kullanıma sunar. tüm kapsamlı hizmetler, istek etkin olduğu sürece geçerlidir.
Not
bağımlılıklarını, 'den hizmetleri çözümlemek yerine oluşturucu parametreleri olarak istekte bulundurmayı tercih RequestServices eder. Bağımlılıkları oluşturucu parametreleri olarak talep etmek, test etmek daha kolay sınıflar oluşturur.
Bağımlılık ekleme için hizmetleri tasarlama
Bağımlılık ekleme için hizmetler tasarlarken:
- Durum bilgisine, statik sınıflara ve üyelere karşı kaçının. Uygulamaları bunun yerine tekli hizmetleri kullanmak üzere tasararak genel durum oluşturmaktan kaçının.
- Hizmetler içindeki bağımlı sınıfların doğrudan örneğini esnleme. Doğrudan örnekleme, kodu belirli bir uygulamaya yönlendirmektedir.
- Hizmetleri küçük, iyi faktörlü ve kolayca test edilmiş hale.
Bir sınıfta çok fazla bağımlılık varsa, sınıfın çok fazla sorumluluğu olduğunu ve Tek Sorumluluk İlkesini (SRP)ihlal ettiğinin bir işareti olabilir. Bazı sorumluluklarını yeni sınıflara dönüştürerek sınıfı yeniden düzenlemeyi deneme. Sayfalar sayfa modeli Razor sınıfları ve MVC denetleyici sınıflarında kullanıcı arabirimi endişelerini dikkate almaları gerektiğini unutmayın.
Hizmetlerin atılması
Kapsayıcı, Dispose oluşturduğu türleri IDisposable arar. Kapsayıcıdan çözümlenen hizmetler hiçbir zaman geliştirici tarafından atılması gerekir. Bir tür veya fabrika tekton olarak kaydedilirse, kapsayıcı singleton'ı otomatik olarak atacaktır.
Aşağıdaki örnekte hizmetler hizmet kapsayıcısı tarafından oluşturulur ve otomatik olarak atılır:
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;
}
}
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;
}
}
public interface IService3
{
public void Write(string message);
}
public class Service3 : IService3, IDisposable
{
private bool _disposed;
public Service3(string myKey)
{
MyKey = myKey;
}
public string MyKey { get; }
public void Write(string message)
{
Console.WriteLine($"Service3: {message}, MyKey = {MyKey}");
}
public void Dispose()
{
if (_disposed)
return;
Console.WriteLine("Service3.Dispose");
_disposed = true;
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<Service1>();
services.AddSingleton<Service2>();
var myKey = Configuration["MyKey"];
services.AddSingleton<IService3>(sp => new Service3(myKey));
services.AddRazorPages();
}
public class IndexModel : PageModel
{
private readonly Service1 _service1;
private readonly Service2 _service2;
private readonly IService3 _service3;
public IndexModel(Service1 service1, Service2 service2, IService3 service3)
{
_service1 = service1;
_service2 = service2;
_service3 = service3;
}
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
Service1.Dispose
Hizmet kapsayıcısı tarafından oluşturulmaz hizmetler
Aşağıdaki kodu inceleyin:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(new Service1());
services.AddSingleton(new Service2());
services.AddRazorPages();
}
Yukarıdaki kodda:
- Hizmet örnekleri hizmet kapsayıcısı tarafından oluşturulmaz.
- Çerçeve hizmetleri otomatik olarak atmaz.
- Hizmetlerden sorumlu geliştiricidir.
Geçici ve paylaşılan örnekler için IDisposable kılavuzu
.NET'te bağımlılık ekleme konusunda Geçici ve paylaşılan örnek için IDisposable kılavuzuna bakın
Varsayılan hizmet kapsayıcısı değiştirme
Bkz. .NET'te bağımlılık eklemede varsayılan hizmet kapsayıcısı değiştirme
Öneriler
.NET Öneriler bağımlılık ekleme içinde bkz.
Hizmet bulucu desenini kullanmaktan kaçının. Örneğin, bunun yerine GetService DI'ı kullanabileceğiniz durumlarda bir hizmet örneği almak için çağırmayın:
Yanlış:

Doğru:
public class MyClass { private readonly IOptionsMonitor<MyOptions> _optionsMonitor; public MyClass(IOptionsMonitor<MyOptions> optionsMonitor) { _optionsMonitor = optionsMonitor; } public void MyMethod() { var option = _optionsMonitor.CurrentValue.Option; ... } }Kaçınılması gereken bir diğer hizmet bulucu varyasyonu da çalışma zamanında bağımlılıkları çözümleten bir fabrikanın eklemesidir. Bu yöntemlerin ikisi de Denetim Stratejilerinin Ters Çevirmesi'nin karışımını sağlar.
için statik
HttpContexterişimden kaçının (örneğin, IHttpContextAccessor.HttpContext).
içinde çağrısı BuildServiceProvider yapmaktan
ConfigureServiceskaçının. ÇağrısıBuildServiceProvidergenellikle geliştirici içinde bir hizmeti çözümlemek istediği zamanConfigureServicesgerçekleşir. Örneğin, yapılandırmadanLoginPathyükleniyor örneğini düşünün. Aşağıdaki yaklaşımdan kaçının:
Yukarıdaki görüntüde, altındaki yeşil dalgalı çizginin seçimi
services.BuildServiceProvideraşağıdaki ASP0000 uyarılarını gösterir:ASP0000 Uygulama kodundan 'BuildServiceProvider' çağrısı yapmak, tekton hizmetlerin ek bir kopyasının oluşturularak sonuç verir. 'Yapılandır'a parametre olarak hizmet ekleme bağımlılığı gibi alternatifleri göz önünde bulundurabilirsiniz.
çağrısı ikinci bir kapsayıcı oluşturur ve bu da kopmuş tektonlar oluşturabilir ve birden çok
BuildServiceProviderkapsayıcıda nesne graflarına başvurulara neden olabilir.Elde etmek için doğru
LoginPathbir yol, seçenekler deseninin DI için yerleşik desteğini kullanmaktır:public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(); services.AddOptions<CookieAuthenticationOptions>( CookieAuthenticationDefaults.AuthenticationScheme) .Configure<IMyService>((options, myService) => { options.LoginPath = myService.GetLoginPath(); }); services.AddRazorPages(); }Atılabilir geçici hizmetler, atılması için kapsayıcı tarafından yakalanır. Bu, üst düzey kapsayıcıdan çözümlenirse bir bellek sızıntısına dönüşebilir.
Uygulamanın kapsamı belirli hizmetleri yakalayan tektonlar olduğundan emin olmak için kapsam doğrulamayı etkinleştirin. Daha fazla bilgi için bkz. Kapsam doğrulaması.
Tüm öneri kümelerine benzer şekilde, bir öneriyi yoksaymanın gerekli olduğu durumlarla karşılaş karşı karşıya olabilirsiniz. Özel durumlar nadirdir, çoğunlukla çerçevenin içinde özel durumlardır.
DI, statik/genel nesne erişim desenlerine alternatiftir. Statik nesne erişimiyle karıştırarak DI'nin avantajlarını fark edeyeyemebilirsiniz.
DI'de çok katmanlılık için önerilen desenler
Core, bulut üzerinde modüler, çok kiracılı uygulamalar için bir uygulama ASP.NET Core. Daha fazla bilgi için, Bkz. Temel Belgeler.
CMS'ye özgü özellikleri olmadan yalnızca Core Framework'leri kullanarak modüler ve çok kiracılı uygulamalar derleme örnekleri için Bkz. Temel Çekirdek örnekleri.
Çerçeve tarafından sağlanan hizmetler
yöntemi, Entity Framework Core ve ASP.NET Core MVC gibi platform özellikleri de dahil olmak üzere Startup.ConfigureServices uygulamanın kullandığı ASP.NET Core kaydedmektedir. Başlangıçta, için IServiceCollection sağlanan, ConfigureServices ana bilgisayarının nasıl yapılandırlandığına bağlı olarak çerçeve tarafından tanımlanan hizmetlere sahip. Çerçeve, uygulama şablonlarına ASP.NET Core uygulamalar için 250'den fazla hizmeti kaydettirmektedir.
Aşağıdaki tabloda bu çerçeve kayıtlı hizmetlerin küçük bir örneği listelemektedir:
| Hizmet Türü | Ömür |
|---|---|
| Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory | Geçi -ci |
| IHostApplicationLifetime | Singleton |
| IWebHostEnvironment | Singleton |
| Microsoft.AspNetCore.Hosting.IStartup | Singleton |
| Microsoft.AspNetCore.Hosting.IStartupFilter | Geçi -ci |
| Microsoft.AspNetCore.Hosting.Server.IServer | Singleton |
| Microsoft.AspNetCore.Http.IHttpContextFactory | Geçi -ci |
| Microsoft.Extensions.Logging.ILogger<TCategoryName> | Singleton |
| Microsoft.Extensions.Logging.ILoggerFactory | Singleton |
| Microsoft.Extensions.ObjectPool.ObjectPoolProvider | Singleton |
| Microsoft.Extensions.Options.IConfigureOptions<TOptions> | Geçi -ci |
| Microsoft.Extensions.Options.IOptions<TOptions> | Singleton |
| System.Diagnostics.DiagnosticSource | Singleton |
| System.Diagnostics.DiagnosticListener | Singleton |
Ek kaynaklar
- ASP.NET Core görünümlere bağımlılık ekleme
- ASP.NET Core denetleyicilere bağımlılık ekleme
- ASP.NET Core'de gereksinim işleyicilere bağımlılık ekleme
- ASP.NET Core Blazor bağımlılık ekleme
- DI uygulaması geliştirme için NDC Konferans Desenleri
- ASP.NET Core 'de uygulama başlatma
- ASP.NET Core 'de fabrika tabanlı ara yazılım etkinleştirmesi
- IDisposables'ın ASP.NET Core
- Bağımlılık Ekleme ile ASP.NET Core Kodu Yazma (MSDN)
- Açık Bağımlılıklar İlkesi
- Denetim Kapsayıcılarının ve Bağımlılık Ekleme Desenini Ters Çevirme (Martin Fowler)
- ASP.NET CORE DI'de birden çok arabirime sahip bir ASP.NET Core kaydetme