Injektáž závislostí v ASP.NET Core
Autor: U. Cekin, Steve Smitha Brandon Suler.
ASP.NET Core podporuje vzor návrhu softwaru injektáže závislostí (DI), což je technika pro dosažení inverze řízení (IoC) mezi třídami a jejich závislostmi.
Další informace týkající se injektáže závislostí v kontrolerů MVC najdete v tématu Injektáž závislostí do kontrolerů v ASP.NET Core .
Informace o použití injektáže závislostí v jiných aplikacích než webových aplikací najdete v tématu Injektáž závislostí v .NET.
Další informace o injektáži závislostí možností najdete v tématu Vzor možností v ASP.NET Core .
Toto téma obsahuje informace o injektáži závislostí v ASP.NET Core. Primární dokumentace k použití injektáže závislostí je součástí injektáže závislostí v .NET.
Zobrazení nebo stažení ukázkového kódu (stažení)
Přehled injektáže závislostí
Závislost je objekt, na který závisí jiný objekt. Prozkoumejte následující MyDependency třídu pomocí WriteMessage metody, na které závisí jiné třídy:
public class MyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
}
}
Třída může vytvořit instanci MyDependency třídy, aby bylo možné použít její WriteMessage metodu. V následujícím příkladu MyDependency je třída závislostí třídy IndexModel :
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency();
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet");
}
}
Třída vytvoří třídu a přímo závisí na MyDependency třídě . Závislosti kódu, například v předchozím příkladu, jsou problematické a měli byste se jim vyhnout z následujících důvodů:
MyDependencyChcete-li nahradit jinou implementací,IndexModelmusí být změněna třída .- Pokud
MyDependencymá závislosti, musí být také nakonfiguroványIndexModeltřídou . Ve velkém projektu s více třídami v závislosti na se konfiguračníMyDependencykód rozřeší v celé aplikaci. - Testování částí této implementace je obtížné.
Injektáž závislostí řeší tyto problémy prostřednictvím:
- Použití rozhraní nebo základní třídy k abstrakci implementace závislostí.
- Registrace závislosti v kontejneru služby ASP.NET Core poskytuje integrovaný kontejner služby IServiceProvider . Služby se obvykle zaregistrovaly v souboru Program.cs aplikace.
- Injektáž služby do konstruktoru třídy, ve které se používá. Tato rozhraní přebírá odpovědnost za vytvoření instance závislosti a jeho likvidaci, když už ji nepotřebujete.
V ukázkové aplikacidefinuje IMyDependency rozhraní WriteMessage metodu :
public interface IMyDependency
{
void WriteMessage(string message);
}
Toto rozhraní je implementováno konkrétním typem MyDependency :
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
Ukázková aplikace zaregistruje IMyDependency službu s konkrétním typem MyDependency . Metoda AddScoped zaregistruje službu s vymezenou životností, životností jednoho požadavku. Doby života služby jsou popsány dále v tomto tématu.
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency>();
var app = builder.Build();
V ukázkové aplikaci se služba IMyDependency vyžádá a použije k volání WriteMessage metody :
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency;
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void OnGet()
{
_myDependency.WriteMessage("Index2Model.OnGet");
}
}
Pomocí vzoru diody, kontroleru nebo Razor stránky:
- Nepoužívejte konkrétní typ
MyDependency, pouzeIMyDependencyrozhraní, které implementuje. To usnadňuje změnu implementace beze změny kontroleru nebo Razor stránky. - Nevytváří instanci , vytvoří ji kontejner ovládacího prvku
MyDependencypro utiliky.
Implementaci rozhraní IMyDependency je možné zlepšit pomocí integrovaného rozhraní API pro protokolování:
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}");
}
}
Aktualizovaný soubor Program.cs zaregistruje novou IMyDependency implementaci:
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency2>();
var app = builder.Build();
MyDependency2 závisí na ILogger<TCategoryName> , který požaduje v konstruktoru. ILogger<TCategoryName> je služba poskytovaná architekturou.
Použití injektáže závislostí zřetězených způsobem není neobvyklé. Každá požadovaná závislost si zase vyžádá vlastní závislosti. Kontejner vyřeší závislosti v grafu a vrátí plně vyřešenou službu. Souhrnná sada závislostí, které je třeba vyřešit, se obvykle označuje jako strom závislostí , graf závislostí nebo graf objektů.
Kontejner se vyřeší tím, že ILogger<TCategoryName> využije (obecné)otevřené typy a eliminuje potřebu registrovat každý (obecný) vytvořený typ.
V terminologii injektáže závislostí služba:
- Je obvykle objekt, který poskytuje službu pro jiné objekty, jako je
IMyDependencynapříklad služba. - Není v souvislosti s webovou službou, i když služba může používat webovou službu.
Rozhraní poskytuje robustní systém protokolování. Implementace uvedené v předchozích příkladech byly napsány za účelem IMyDependency předvedení základního inistrování, nikoli implementace protokolování. Většina aplikací by neměla psát protokolovací nástroje. Následující kód ukazuje použití výchozího protokolování, které nevyžaduje registraci žádné služby:
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);
}
}
Pomocí předchozího kódu není nutné aktualizovat soubor Program.cs, protože protokolování poskytuje rozhraní .
Služby vloženého do souboru Program.c
V souboru Program.cs je možné přeložit jakoukoli službu zaregistrovanou v kontejneru app.Services IN:
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IMyDependency, MyDependency>();
var app = builder.Build();
Registrace skupin služeb pomocí rozšiřujících metod
Rozhraní ASP.NET Core používá konvenci pro registraci skupiny souvisejících služeb. Tato konvence slouží k registraci všech služeb vyžadované funkcí Add{GROUP_NAME} architektury pomocí jedné metody rozšíření. Metoda rozšíření například AddControllers zaregistruje služby vyžadované pro kontrolery MVC.
Následující kód je vygenerován šablonou Pages pomocí jednotlivých uživatelských účtů a ukazuje, jak přidat další služby do kontejneru pomocí Razor rozšiřujících metod AddDbContext a 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();
Zvažte následující, který registruje služby a konfiguruje možnosti:
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();
Související skupiny registrací je možné přesunout do metody rozšíření pro registraci služeb. Například konfigurační služby jsou přidány do následující třídy:
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;
}
}
}
Zbývající služby jsou zaregistrované v podobné třídě. Následující kód používá nové metody rozšíření k registraci služeb:
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddConfig(builder.Configuration)
.AddMyDependencyGroup();
builder.Services.AddRazorPages();
var app = builder.Build();
Poznámka: Každá services.Add{GROUP_NAME} metoda rozšíření přidává a potenciálně konfiguruje služby. Například přidá řadiče MVC služeb s vyžadováním zobrazení a přidá AddControllersWithViews AddRazorPages služby, které Razor stránky vyžadují. Doporučujeme, aby aplikace postupují podle konvence vytváření názvů metod rozšíření v oboru Microsoft.Extensions.DependencyInjection názvů . Vytváření rozšiřujících metod v oboru Microsoft.Extensions.DependencyInjection názvů :
- Zapouzdřuje skupiny registrací služeb.
- Poskytuje pohodlný přístup IntelliSense ke službě.
Doby života služby
Viz Životnosti služeb v injektáži závislostí v .NET.
Pokud chcete v middlewaru používat vymezené služby, použijte jeden z následujících přístupů:
- Vloží službu do middlewaru
InvokeneboInvokeAsyncmetody . Injektáž konstruktoru vyvolá výjimku modulu runtime, protože vynutí, aby se služba s vymezeným oborem chovala jako jedna instance. Tento přístup ukazuje ukázka v části Možnosti doby života aInvokeAsyncregistrace. - Použijte middleware založený na továrně. Middleware zaregistrovaný tímto přístupem se aktivuje pro každý požadavek klienta (připojení), což umožňuje vloženého do metody middlewaru služby s vymezenou
InvokeAsyncoborem.
Další informace naleznete v tématu Psaní vlastních ASP.NET Core middlewaru.
Metody registrace služby
Viz Metody registrace služby v injektáži závislostí v .NET.
Při napodození typů pro testování se běžně používá více implementací.
Registrace služby pouze s typem implementace je ekvivalentní k registraci této služby se stejnou implementací a typem služby. To je důvod, proč více implementací služby nelze zaregistrovat pomocí metod, které nevezměte explicitní typ služby. Tyto metody mohou registrovat více instancí služby, ale všechny budou mít stejný typ implementace.
Jakoukoli z výše uvedených metod registrace služby je možné použít k registraci více instancí služby stejného typu. V následujícím příkladu AddSingleton je volána dvakrát s IMyDependency typem služby. Druhé volání přepíše předchozí volání, pokud je vyřešeno jako , a přidá k předchozímu volání, pokud je více služeb AddSingleton IMyDependency vyřešeno prostřednictvím IEnumerable<IMyDependency> . Služby se zobrazí v pořadí, v pořadí, ve které byly zaregistrovány při řešení prostřednictvím 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);
}
}
Chování injektáže konstruktoru
Viz Chování injektáže konstruktoru v injektáži závislostí v rozhraní .NET.
Entity Framework kontexty
Ve výchozím nastavení Entity Framework kontejneru služby s použitím vymezené doby života, protože operace databáze webové aplikace jsou obvykle vymezené na požadavek klienta. Pokud chcete použít jinou dobu života, určete dobu života pomocí AddDbContext přetížení. Služby daného životního cyklu by neměly používat kontext databáze s životností kratší než doba života služby.
Možnosti doby života a registrace
Chcete-li předvést rozdíl mezi životností služby a jejich možnostmi registrace, zvažte následující rozhraní, která představují úlohu jako operaci s identifikátorem OperationId . V závislosti na tom, jak je doba života služby operace nakonfigurovaná pro následující rozhraní, poskytuje kontejner na žádost třídy stejné nebo různé instance služby:
public interface IOperation
{
string OperationId { get; }
}
public interface IOperationTransient : IOperation { }
public interface IOperationScoped : IOperation { }
public interface IOperationSingleton : IOperation { }
Následující Operation třída implementuje všechna předchozí rozhraní. Konstruktor Operation vygeneruje identifikátor GUID a uloží poslední 4 znaky do OperationId vlastnosti :
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
public Operation()
{
OperationId = Guid.NewGuid().ToString()[^4..];
}
public string OperationId { get; }
}
Následující kód vytvoří několik registrací třídy Operation podle pojmenovaných životností:
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();
Ukázková aplikace ukazuje životnost objektů v rámci požadavků i mezi nimi. A IndexModel middleware požadavek každý druh IOperation typu a protokolu pro každý z OperationId nich:
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);
}
}
Podobně jako IndexModel middleware překládá stejné služby:
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>();
}
}
Vymezené služby musí být vyřešeny v InvokeAsync metodě :
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);
}
Výstup protokolovacího nástroje ukazuje:
- Přechodné objekty se vždycky liší. Přechodná
OperationIdhodnota se liší vIndexModela v middlewaru. - Vymezené objekty jsou pro daný požadavek stejné, ale v každé nové žádosti se liší.
- Objekty singleton jsou pro každý požadavek stejné.
Chcete-li snížit výstup protokolování, nastavte v souboru appSettings položku Logging: LogLevel: Microsoft: Error . Soubor Development. JSON :
{
"MyKey": "MyKey from appsettings.Developement.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Debug",
"Microsoft": "Error"
}
}
}
Vyřešit službu při spuštění aplikace
Následující kód ukazuje, jak vyřešit vymezenou službu po omezené trvání při spuštění aplikace:
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();
Ověřování oboru
Viz chování injektáže konstruktoru v Injektáže závislostí v .NET .
Další informace najdete v tématu ověřování oboru.
Žádosti o služby
služby a jejich závislosti v rámci žádosti ASP.NET Core jsou zpřístupněny prostřednictvím HttpContext.RequestServices .
Architektura vytvoří obor na žádost a RequestServices zpřístupňuje vymezeného poskytovatele služeb. Všechny oborové služby platí, pokud je žádost aktivní.
Poznámka
Preferovat požadavky na závislosti jako parametry konstruktoru při překládání služeb z RequestServices . Vyžadování závislostí jako parametrů konstruktoru poskytuje třídy, které jsou snáze testovány.
Navrhnout služby pro vkládání závislostí
Při navrhování služeb pro vkládání závislostí:
- Vyhněte se stavovým, statickým třídám a členům. Vyhněte se vytváření globálního stavu tím, že aplikace navrhujete, aby místo toho používaly služby singleton.
- Vyhněte se přímému vytváření instancí závislých tříd v rámci služeb. Přímá instance Couples kód na konkrétní implementaci.
- Vytvářejte služby s malým, dobře faktoringem a snadnou otestováním.
Pokud má třída mnoho vložených závislostí, může se jednat o znaménko, že třída má příliš mnoho zodpovědnosti a je v rozporu s principem jediné zodpovědnosti (SRP). Pokuste se Refaktorovat třídu přesunutím některých jeho odpovědností do nových tříd. Mějte na paměti, že Razor stránky tříd modelu stránky a třídy KONTROLERU MVC by se měly zaměřit na uživatelské rozhraní.
Vyřazení služeb
Kontejner volá Dispose typy, které IDisposable vytvoří. Služby vyřešené z kontejneru by nikdy neměly být odstraněny vývojářem. Pokud je typ nebo objekt pro vytváření zaregistrován jako singleton, kontejner odstraní singleton automaticky.
V následujícím příkladu jsou služby vytvořeny pomocí kontejneru služby a automaticky odstraněny: 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");
}
}
Konzola ladění po každé aktualizaci stránky indexu zobrazí následující výstup:
Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet
Service1.Dispose
Služby, které nevytvořil kontejner služby
Vezměme si následující kód:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSingleton<Service1>();
builder.Services.AddSingleton<Service2>();
V předchozím kódu:
- Instance služby nejsou vytvořeny kontejnerem služby.
- Rozhraní neodstraní služby automaticky.
- Vývojář zodpovídá za likvidaci služeb.
Doprovodné materiály k rozhraní IDisposable pro přechodné a sdílené instance
Viz návod IDisposable pro přechodnou a sdílenou instanci v Injektáže závislosti v .NET .
Výchozí nahrazení kontejneru služby
Viz výchozí nahrazení kontejneru služby v Injektáže závislostí v .NET .
Doporučení
viz Recommendations v injektáže závislosti v .net .
Vyhněte se použití vzoru lokátoru služby. Například Nevolejte GetService pro získání instance služby, když můžete místo toho použít di:
Nesprávně:

Správné:
public class MyClass { private readonly IOptionsMonitor<MyOptions> _optionsMonitor; public MyClass(IOptionsMonitor<MyOptions> optionsMonitor) { _optionsMonitor = optionsMonitor; } public void MyMethod() { var option = _optionsMonitor.CurrentValue.Option; ... } }Další změnou lokátoru služby, aby se zabránilo, je vložení továrny, která vyřeší závislosti za běhu. Oba tyto postupy kombinují inverze strategií řízení .
Vyhněte se statickému přístupu k
HttpContext(například IHttpContextAccessor. HttpContext).
DI je alternativou ke vzorům statických nebo globálních přístupů k objektům. Je možné, že nebudete moci využít výhody DI, pokud je kombinujete se statickým přístupem k objektům.
Doporučené vzory pro víceklientské architektury v DI
Sadu jader je aplikační architektura pro vytváření modulárních aplikací s více klienty na ASP.NET Core. Další informace najdete v dokumentaci k sadě sad.
V ukázkách Core Core najdete příklady vytváření modulárních a víceklientské aplikací s využitím jenom sady Core Core Framework bez jakýchkoli funkcí specifických pro CMS.
Služby poskytované rozhraním
Program. cs registruje služby, které aplikace používá, včetně funkcí platformy, jako je Entity Framework Core a ASP.NET Core MVC. Zpočátku jsou služby, které jsou IServiceCollection k dispozici pro program. cs , definovány v závislosti na tom, jak byl hostitel nakonfigurovaný. pro aplikace založené na šablonách ASP.NET Core registruje rozhraní více než 250 služeb.
V následující tabulce je uveden malý vzorek těchto služeb registrovaných v rozhraní:
| Typ služby | Doba platnosti |
|---|---|
| Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory | Dočasný |
| IHostApplicationLifetime | Singleton |
| IWebHostEnvironment | Singleton |
| Microsoft.AspNetCore.Hosting.IStartup | Singleton |
| Microsoft.AspNetCore.Hosting.IStartupFilter | Dočasný |
| Microsoft.AspNetCore.Hosting.Server.IServer | Singleton |
| Microsoft.AspNetCore.Http.IHttpContextFactory | Dočasný |
| Microsoft.Extensions.Logging.ILogger<TCategoryName> | Singleton |
| Microsoft.Extensions.Logging.ILoggerFactory | Singleton |
| Microsoft.Extensions.ObjectPool.ObjectPoolProvider | Singleton |
| Microsoft.Extensions.Options.IConfigureOptions<TOptions> | Dočasný |
| Microsoft.Extensions.Options.IOptions<TOptions> | Singleton |
| System.Diagnostics.DiagnosticSource | Singleton |
| System.Diagnostics.DiagnosticListener | Singleton |
Další zdroje informací
- Injektáž závislostí do zobrazení v ASP.NET Core
- Injektáž závislostí do kontrolerů v ASP.NET Core
- Injektáž závislostí v obslužných rutinách požadavků ASP.NET Core
- ASP.NET Core Blazor vkládání závislostí
- NORWEGIAN Developers Conference se vzory konferencí pro vývoj aplikací pro DI
- Spuštění aplikace v ASP.NET Core
- Aktivace middlewaru založená na továrně v ASP.NET Core
- Čtyři způsoby, jak vyřadit IDisposable v ASP.NET Core
- zápis čistého kódu v ASP.NET Core pomocí injektáže závislosti (MSDN)
- Explicitní závislosti – princip
- Inverze řídicích kontejnerů a vzor injektáže závislosti (Martin Fowlera)
- jak zaregistrovat službu s více rozhraními v ASP.NET Core DI
Od Kirka Larkin, Steve Smith, Scott Addiea Brandon Dahler
ASP.NET Core podporuje vzor návrhu softwaru pro vkládání závislostí (DI), což je technika pro dosažení inverze ovládacího prvku (IoC) mezi třídami a jejich závislostmi.
Další informace, které jsou specifické pro vkládání závislostí v rámci řadičů MVC, najdete v tématu Injektáž závislostí do kontrolerů v ASP.NET Core .
Informace o použití injektáže závislosti v jiných aplikacích než ve webových aplikacích naleznete v tématu Injektáže závislosti v rozhraní .NET.
Další informace o vkládání závislostí z možností naleznete v tématu Vzor možností v ASP.NET Core .
Toto téma poskytuje informace o vkládání závislostí v ASP.NET Core. Primární dokumentace k používání vkládání závislostí je obsažená v vkládání závislostí v rozhraní .NET.
Zobrazit nebo stáhnout ukázkový kód (Jak stáhnout)
Přehled injektáže závislosti
Závislost je objekt, na kterém je závislý jiný objekt. Projděte si následující MyDependency třídu s WriteMessage metodou, na které jsou závislé jiné třídy:
public class MyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
}
}
Třída může vytvořit instanci MyDependency třídy, aby bylo možné využít její WriteMessage metodu. V následujícím příkladu MyDependency je třída závislostí IndexModel třídy:
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency();
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet created this message.");
}
}
Třída vytvoří a přímo závisí na MyDependency třídě. Závislosti kódu, jako v předchozím příkladu, jsou problematické a je třeba se jim vyhnout z následujících důvodů:
MyDependencyChcete-li nahradit jinou implementací,IndexModelmusí být třída upravena.- Pokud
MyDependencymá závislosti, musí být také nakonfiguroványIndexModeltřídou . Ve velkém projektu s více třídami v závislosti na se konfiguračníMyDependencykód rozřeší v celé aplikaci. - Testování částí této implementace je obtížné. Aplikace by měla používat napodobné nebo zástupné třídy, což u tohoto přístupu
MyDependencynení možné.
Injektáž závislostí řeší tyto problémy prostřednictvím:
- Použití rozhraní nebo základní třídy k abstrakci implementace závislostí.
- Registrace závislosti v kontejneru služby ASP.NET Core poskytuje integrovaný kontejner služby IServiceProvider . Služby se obvykle zaregistrovaly v metodě
Startup.ConfigureServicesaplikace. - Injektáž služby do konstruktoru třídy, ve které se používá. Tato rozhraní přebírá odpovědnost za vytvoření instance závislosti a jeho likvidaci, když už ji nepotřebujete.
V ukázkové aplikacidefinuje IMyDependency rozhraní WriteMessage metodu :
public interface IMyDependency
{
void WriteMessage(string message);
}
Toto rozhraní je implementováno konkrétním typem MyDependency :
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
Ukázková aplikace zaregistruje IMyDependency službu s konkrétním typem MyDependency . Metoda AddScoped zaregistruje službu s vymezenou životností, životností jednoho požadavku. Doby života služby jsou popsány dále v tomto tématu.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddRazorPages();
}
V ukázkové aplikaci se služba IMyDependency vyžádá a použije k volání WriteMessage metody :
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency;
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void OnGet()
{
_myDependency.WriteMessage("Index2Model.OnGet");
}
}
Pomocí vzoru DI kontroler:
- Nepoužívejte konkrétní typ
MyDependency, pouzeIMyDependencyrozhraní, které implementuje. To usnadňuje změnu implementace, kterou kontroler používá, beze změny kontroleru. - Nevytváří instanci , vytvoří ji kontejner ovládacího prvku
MyDependencypro utiliky.
Implementaci rozhraní IMyDependency je možné zlepšit pomocí integrovaného rozhraní API pro protokolování:
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}");
}
}
ConfigureServicesAktualizovaná metoda zaregistruje novou IMyDependency implementaci:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency2>();
services.AddRazorPages();
}
MyDependency2 závisí na ILogger<TCategoryName> , který požaduje v konstruktoru. ILogger<TCategoryName> je služba poskytovaná architekturou.
Použití injektáže závislostí zřetězených způsobem není neobvyklé. Každá požadovaná závislost si zase vyžádá vlastní závislosti. Kontejner vyřeší závislosti v grafu a vrátí plně vyřešenou službu. Souhrnná sada závislostí, které je třeba vyřešit, se obvykle označuje jako strom závislostí , graf závislostí nebo graf objektů.
Kontejner se vyřeší tím, že ILogger<TCategoryName> využije (obecné)otevřené typy a eliminuje potřebu registrovat každý (obecný) vytvořený typ.
V terminologii injektáže závislostí služba:
- Je obvykle objekt, který poskytuje službu pro jiné objekty, jako je
IMyDependencynapříklad služba. - Není v souvislosti s webovou službou, i když služba může používat webovou službu.
Rozhraní poskytuje robustní systém protokolování. Implementace uvedené v předchozích příkladech byly napsány za účelem IMyDependency předvedení základního inistrování, nikoli implementace protokolování. Většina aplikací by neměla psát protokolovací nástroje. Následující kód ukazuje použití výchozího protokolování, které nevyžaduje registraci žádné služby v 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);
}
}
Pomocí předchozího kódu není nutné aktualizovat ConfigureServices , protože protokolování poskytuje rozhraní .
Služby vloženého do spuštění
Služby lze injektovat do Startup konstruktoru a Startup.Configure metody .
Při použití obecného hostitele ( ) je možné do konstruktoru vloženého pouze Startup následující služby IHostBuilder :
Do metody je možné vloženého jakoukoli službu zaregistrovanou v kontejneru Startup.Configure IN:
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
...
}
Další informace najdete v tématu a Spuštění aplikace v ASP.NET Core Konfigurace přístupu ve spouštěcím souboru.
Registrace skupin služeb pomocí rozšiřujících metod
Rozhraní ASP.NET Core používá konvenci pro registraci skupiny souvisejících služeb. Tato konvence slouží k registraci všech služeb vyžadované funkcí Add{GROUP_NAME} architektury pomocí jedné metody rozšíření. Metoda rozšíření například AddControllers zaregistruje služby vyžadované pro kontrolery MVC.
Následující kód je vygenerován šablonou Pages pomocí jednotlivých uživatelských účtů a ukazuje, jak přidat další služby do kontejneru pomocí Razor rozšiřujících metod AddDbContext a 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();
}
Vezměte v úvahu následující ConfigureServices metodu, která registruje služby a nakonfiguruje možnosti:
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();
}
Související skupiny registrací lze přesunout do metody rozšíření pro registraci služeb. Například konfigurační služby jsou přidány do následující třídy:
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;
}
}
}
Zbývající služby jsou registrovány v podobné třídě. Následující ConfigureServices Metoda používá nové metody rozšíření k registraci služeb:
public void ConfigureServices(IServiceCollection services)
{
services.AddConfig(Configuration)
.AddMyDependencyGroup();
services.AddRazorPages();
}
Poznámka: Každá services.Add{GROUP_NAME} metoda rozšíření přidá a případně nakonfiguruje služby. Například AddControllersWithViews přidá řadiče služby MVC s zobrazeními vyžaduje a AddRazorPages přidá Razor stránky služeb. Doporučujeme, aby aplikace dodržovaly zásady vytváření názvů pro vytváření rozšiřujících metod v Microsoft.Extensions.DependencyInjection oboru názvů. Vytváření rozšiřujících metod v Microsoft.Extensions.DependencyInjection oboru názvů:
- Zapouzdřuje skupiny registrací služby.
- Poskytuje pohodlný přístup k službě IntelliSense .
Doby života služby
Viz Životnosti služeb v injektáži závislostí v .NET.
Pokud chcete v middlewaru používat vymezené služby, použijte jeden z následujících přístupů:
- Vloží službu do middlewaru
InvokeneboInvokeAsyncmetody . Injektáž konstruktoru vyvolá výjimku modulu runtime, protože vynutí, aby se služba s vymezeným oborem chovala jako jedna instance. Tento přístup ukazuje ukázka v části Možnosti doby života aInvokeAsyncregistrace. - Použijte middleware založený na továrně. Middleware zaregistrovaný tímto přístupem se aktivuje pro každý požadavek klienta (připojení), což umožňuje vloženého do metody middlewaru služby s vymezenou
InvokeAsyncoborem.
Další informace naleznete v tématu Psaní vlastních ASP.NET Core middlewaru.
Metody registrace služby
Viz Metody registrace služby v injektáži závislostí v .NET.
Při napodození typů pro testování se běžně používá více implementací.
Registrace služby pouze s typem implementace je ekvivalentní k registraci této služby se stejnou implementací a typem služby. To je důvod, proč více implementací služby nelze zaregistrovat pomocí metod, které nevezměte explicitní typ služby. Tyto metody mohou registrovat více instancí služby, ale všechny budou mít stejný typ implementace.
Jakoukoli z výše uvedených metod registrace služby je možné použít k registraci více instancí služby stejného typu. V následujícím příkladu AddSingleton je volána dvakrát s IMyDependency typem služby. Druhé volání přepíše předchozí volání, pokud je vyřešeno jako , a přidá k předchozímu volání, pokud je více služeb AddSingleton IMyDependency vyřešeno prostřednictvím IEnumerable<IMyDependency> . Služby se zobrazí v pořadí, v pořadí, ve které byly zaregistrovány při řešení prostřednictvím 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);
}
}
Chování injektáže konstruktoru
Viz Chování injektáže konstruktoru v injektáži závislostí v rozhraní .NET.
Entity Framework kontexty
Ve výchozím nastavení Entity Framework kontejneru služby s použitím vymezené doby života, protože operace databáze webové aplikace jsou obvykle vymezené na požadavek klienta. Pokud chcete použít jinou dobu života, určete dobu života pomocí AddDbContext přetížení. Služby daného životního cyklu by neměly používat kontext databáze s životností kratší než doba života služby.
Možnosti doby života a registrace
Chcete-li předvést rozdíl mezi životností služby a jejich možnostmi registrace, zvažte následující rozhraní, která představují úlohu jako operaci s identifikátorem OperationId . V závislosti na tom, jak je doba života služby operace nakonfigurovaná pro následující rozhraní, poskytuje kontejner na žádost třídy stejné nebo různé instance služby:
public interface IOperation
{
string OperationId { get; }
}
public interface IOperationTransient : IOperation { }
public interface IOperationScoped : IOperation { }
public interface IOperationSingleton : IOperation { }
Následující Operation třída implementuje všechna předchozí rozhraní. Konstruktor Operation vygeneruje identifikátor GUID a uloží poslední 4 znaky do OperationId vlastnosti :
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
public Operation()
{
OperationId = Guid.NewGuid().ToString()[^4..];
}
public string OperationId { get; }
}
Metoda Startup.ConfigureServices vytvoří více registrací třídy podle Operation pojmenovaných životností:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddRazorPages();
}
Ukázková aplikace ukazuje životnost objektů v rámci požadavků i mezi nimi. A IndexModel middleware požadavek každý druh IOperation typu a protokolu pro každý z OperationId nich:
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);
}
}
Podobně jako IndexModel middleware překládá stejné služby:
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>();
}
}
Vymezené služby musí být vyřešeny v InvokeAsync metodě :
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);
}
Výstup protokolovacího nástroje ukazuje:
- Přechodné objekty se vždycky liší. Přechodná
OperationIdhodnota se v a vIndexModelmiddlewaru liší. - Vymezené objekty jsou pro daný požadavek stejné, ale liší se v rámci každého nového požadavku.
- Jednotlivé objekty jsou pro každý požadavek stejné.
Pokud chcete snížit výstup protokolování, nastavte v nastavení aplikace Logging:LogLevel:Microsoft:Error. Soubor Development.json:
{
"MyKey": "MyKey from appsettings.Developement.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Debug",
"Microsoft": "Error"
}
}
}
Volání služeb z hlavní
Vytvořte s IServiceScope IServiceScopeFactory.CreateScope překlad služby s vymezenou oborem v rámci oboru aplikace. Tento přístup je užitečný pro přístup k vymezené službě při spuštění za běhu úloh inicializace.
Následující příklad ukazuje, jak získat přístup k vymezené službě a IMyDependency volat její WriteMessage metodu v 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>();
});
}
Ověření oboru
Viz Chování injektáže konstruktoru v injektáži závislostí v rozhraní .NET.
Další informace najdete v tématu Ověření oboru.
Žádosti o služby
Služby a jejich závislosti v rámci požadavku ASP.NET Core prostřednictvím HttpContext.RequestServices .
Rozhraní vytvoří obor pro každý požadavek a RequestServices zpřístupňuje vymezené poskytovatele služeb. Všechny vymezené služby jsou platné po dobu, po které je požadavek aktivní.
Poznámka
Preferujete vyžadování závislostí jako parametrů konstruktoru před překladem služeb z RequestServices . Požadavek na závislosti jako parametry konstruktoru přináší třídy, které se snadněji testuje.
Návrh služeb pro injektáž závislostí
Při navrhování služeb pro injektáž závislostí:
- Vyhněte se stavové, statické třídy a členy. Vyhněte se vytváření globálního stavu tím, že aplikace místo toho používají jednosměnné služby.
- Vyhněte se přímé vytváření instancí závislých tříd v rámci služeb. Přímá instance zomení kód na konkrétní implementaci.
- Zajistěte, aby byly služby malé, dobře faktorované a snadno otestované.
Pokud třída obsahuje velké množství vloženého závislostí, může to být známkou toho, že třída má příliš mnoho zodpovědností a porušuje princip jedné odpovědnosti (SRP). Pokuste se refaktorovat třídu přesunutím některých jejích zodpovědností do nových tříd. Mějte na paměti, že třídy stránkového modelu Pages a třídy Razor kontroleru MVC by se měly zaměřit na otázky uživatelského rozhraní.
Vyřazení služeb
Kontejner volá Dispose IDisposable typy, které vytvoří. Služby vyřešené z kontejneru by vývojář nikdy neměl likvidovat. Pokud je typ nebo objekt pro vytváření zaregistrovaný jako singleton, kontejner jeden prvek automaticky uchová.
V následujícím příkladu jsou služby vytvořeny kontejnerem služby a automaticky odstraněny:
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");
}
}
Konzola ladění po každé aktualizaci stránky Index zobrazí následující výstup:
Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet
Service1.Dispose
Služby nevytycené kontejnerem služby
Vezměme si následující kód:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(new Service1());
services.AddSingleton(new Service2());
services.AddRazorPages();
}
V předchozím kódu:
- Instance služby nejsou vytvořeny kontejnerem služby.
- Rozhraní nezbavuje služeb automaticky.
- Vývojář zodpovídá za likvidaci služeb.
Pokyny iDisposable pro přechodné a sdílené instance
Informace o přechodných a sdílených instancích v injektáži závislostí v rozhraní .NET najdete v pokynech pro rozhraní IDisposable.
Nahrazení výchozího kontejneru služby
Viz Výchozí náhrada kontejneru služby v injektáži závislostí v .NET.
Doporučení
Viz Recommendations injektáž závislostí v .NET.
Vyhněte se použití vzoru lokátoru služby. Například nevolat k GetService získání instance služby, pokud můžete místo toho použít DI:
Nesprávně:

Správně:
public class MyClass { private readonly IOptionsMonitor<MyOptions> _optionsMonitor; public MyClass(IOptionsMonitor<MyOptions> optionsMonitor) { _optionsMonitor = optionsMonitor; } public void MyMethod() { var option = _optionsMonitor.CurrentValue.Option; ... } }Další variantou lokátoru služby, které je třeba se vyhnout, je vložení továrny, která řeší závislosti za běhu. Oba tyto postupy kombinovat strategie inverze řízení.
Vyhněte se statickému
HttpContextpřístupu k (například IHttpContextAccessor.HttpContext).
Vyhněte se volání BuildServiceProvider metody v
ConfigureServices. VoláníBuildServiceProviderobvykle nastane, když vývojář chce vyřešit službu vConfigureServices. Představte si například případ, kdyLoginPathje načten z konfigurace . Vyhněte se následujícímu přístupu:
Na předchozím obrázku se po výběru zelené vlnovkové čáry pod
services.BuildServiceProviderzobrazí následující upozornění ASP0000:Volání metody BuildServiceProvider z kódu aplikace v ASP0000 má za výsledek vytvoření další kopie jedné instance služeb. Jako parametry konfigurace zvažte alternativy, jako je vkládání závislostí služeb.
Voláním metody se vytvoří druhý kontejner, který může vytvořit roztržené jednotlivé objekty a způsobit odkazy na grafy objektů
BuildServiceProviderve více kontejnerech.Správným způsobem, jak získat, je použít integrovanou podporu pro induici v modelu
LoginPathmožností: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(); }Jednorázová přechodná služba je zachycena kontejnerem k vyřazení. To se může při vyřešení z kontejneru nejvyšší úrovně změnit na nevrácenou paměť.
Povolte ověřování oboru, abyste se ujistili, že aplikace nemá jednotlivé prvky, které zachycuje služby s vymezeným oborem. Další informace najdete v tématu Ověření oboru.
Stejně jako u všech sad doporučení můžete narazit na situace, kdy je potřeba doporučení ignorovat. Výjimky jsou vzácné, většinou se jedná o speciální případy v rámci samotné architektury.
Di je alternativou ke statickým a globálním vzorům přístupu k objektům. Možná nebudete moct využívat výhody diody, pokud ho zmícháte se statickým přístupem k objektům.
Doporučené vzory pro vícetádová prostředí v induividuálnosti
Core je aplikační architektura pro vytváření modulárních více tenantových aplikací na ASP.NET Core. Další informace najdete v dokumentaci k produktu
Příklady vytváření modulárních a více tenantových aplikací pouze s využitím architektury Nam Core Framework bez některé z jejích funkcí specifických pro CMS najdete v ukázkách Pro Core.
Služby poskytované architekturou
Metoda zaregistruje služby, které aplikace používá, včetně funkcí platformy, jako jsou Entity Framework Core a Startup.ConfigureServices ASP.NET Core MVC. Na začátku má poskytované služby definované architekturou v závislosti na tom, IServiceCollection ConfigureServices jak byl hostitel nakonfigurovaný. U aplikací založených na ASP.NET Core šablonách rozhraní registruje více než 250 služeb.
Následující tabulka uvádí malou ukázku těchto služeb zaregistrovaných v rámci architektury:
| Typ služby | Doba platnosti |
|---|---|
| Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory | Přechodné |
| IHostApplicationLifetime | Singleton |
| IWebHostEnvironment | Singleton |
| Microsoft.AspNetCore.Hosting.IStartup | Singleton |
| Microsoft.AspNetCore.Hosting.IStartupFilter | Přechodné |
| Microsoft.AspNetCore.Hosting.Server.IServer | Singleton |
| Microsoft.AspNetCore.Http.IHttpContextFactory | Přechodné |
| Microsoft.Extensions.Logging.ILogger<TCategoryName> | Singleton |
| Microsoft.Extensions.Logging.ILoggerFactory | Singleton |
| Microsoft.Extensions.ObjectPool.ObjectPoolProvider | Singleton |
| Microsoft.Extensions.Options.IConfigureOptions<TOptions> | Přechodné |
| Microsoft.Extensions.Options.IOptions<TOptions> | Singleton |
| System.Diagnostics.DiagnosticSource | Singleton |
| System.Diagnostics.DiagnosticListener | Singleton |
Další zdroje informací
- Injektáž závislostí do zobrazení v ASP.NET Core
- Injektáž závislostí do kontrolerů v ASP.NET Core
- Injektáž závislostí v obslužných rutinách požadavků ASP.NET Core
- ASP.NET Core Blazor vkládání závislostí
- Vzory konference NDC pro vývoj aplikací pro di
- Spuštění aplikace v ASP.NET Core
- Aktivace middlewaru založená na továrně v ASP.NET Core
- Čtyři způsoby uvolnění rozhraní IDisposables v ASP.NET Core
- Psaní čistého kódu v ASP.NET Core injektáží závislostí (MSDN)
- Princip explicitních závislostí
- Inverze kontejnerů ovládacích prvků a vzor injektáže závislostí (Martin Fowler)
- Postup registrace služby s více rozhraními v ASP.NET Core instrukce