ASP.NET Core Blazor bağımlılık ekleme

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Tarafından Rainer Stropek ve Mike Rousos

Bu makalede uygulamaların bileşenlere nasıl Blazor hizmet ekleyebileceğiniz açıklanmaktadır.

Bağımlılık ekleme (DI), merkezi bir konumda yapılandırılan hizmetlere erişmek için kullanılan bir tekniktir:

  • Çerçeveye kayıtlı hizmetler doğrudan bileşenlere Razor eklenebilir.
  • Blazor uygulamalar özel hizmetleri tanımlar ve kaydeder ve DI aracılığıyla uygulama genelinde kullanılabilir hale getirir.

Not

Bu konuyu okumadan önce ASP.NET Core'da bağımlılık ekleme konusunu okumanızı öneririz.

Varsayılan hizmetler

Aşağıdaki tabloda gösterilen hizmetler genellikle uygulamalarda kullanılır Blazor .

Hizmet Yaşam süresi Açıklama
HttpClient Kapsamlı

URI tarafından tanımlanan bir kaynaktan HTTP istekleri göndermek ve HTTP yanıtları almak için yöntemler sağlar.

İstemci tarafında, örneğinin bir örneği HttpClient dosyada Program uygulama tarafından kaydedilir ve arka planda HTTP trafiğini işlemek için tarayıcıyı kullanır.

Sunucu tarafı, HttpClient varsayılan olarak bir hizmet olarak yapılandırılmaz. Sunucu tarafı kodunda bir HttpClientsağlayın.

Daha fazla bilgi için bkz . ASP.NET Core Blazor uygulamasından web API'sini çağırma.

, HttpClient tekil olarak değil kapsamlı bir hizmet olarak kaydedilir. Daha fazla bilgi için Hizmet ömrü bölümüne bakın.

IJSRuntime

İstemci tarafı: Singleton

Sunucu tarafı: Kapsamlı

Çerçeve, Blazor uygulamanın hizmet kapsayıcısında kaydeder IJSRuntime .

JavaScript çağrılarının gönderildiği bir JavaScript çalışma zamanının örneğini temsil eder. Daha fazla bilgi için bkz. ASP.NET Core Blazor'da .NET yöntemlerinden JavaScript işlevlerini çağırma.

Hizmeti sunucudaki tek bir hizmete eklemek istediğinizde aşağıdaki yaklaşımlardan birini uygulayın:

  • Hizmet kaydını, 'nin kaydıyla eşleşecek IJSRuntimeşekilde kapsamlı olarak değiştirin; bu, hizmet kullanıcıya özgü durumla ilgilenirse uygun olur.
  • yönteminin IJSRuntime bağımsız değişkeni olarak singleton hizmetine eklemek yerine singleton hizmetinin uygulamasına geçirin.
NavigationManager

İstemci tarafı: Singleton

Sunucu tarafı: Kapsamlı

Çerçeve, Blazor uygulamanın hizmet kapsayıcısında kaydeder NavigationManager .

URI'lerle ve gezinti durumuyla çalışmaya yönelik yardımcılar içerir. Daha fazla bilgi için bkz . URI ve gezinti durumu yardımcıları.

Çerçeve tarafından Blazor kaydedilen ek hizmetler, yapılandırma ve günlüğe kaydetme gibi özellikleri açıklamak Blazor için kullanıldıkları belgelerde açıklanmıştır.

Özel hizmet sağlayıcısı tabloda listelenen varsayılan hizmetleri otomatik olarak sağlamaz. Özel bir hizmet sağlayıcısı kullanıyorsanız ve tabloda gösterilen hizmetlerden herhangi birini gerektiriyorsanız, gerekli hizmetleri yeni hizmet sağlayıcısına ekleyin.

İstemci tarafı hizmetleri ekleme

Dosyadaki uygulamanın hizmet koleksiyonu Program için hizmetleri yapılandırın. Aşağıdaki örnekte, ExampleDependency uygulaması için IExampleDependencykaydedilir:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.Services.AddSingleton<IExampleDependency, ExampleDependency>();
...

await builder.Build().RunAsync();

Konak oluşturulduktan sonra, tüm bileşenler işlenmeden önce kök DI kapsamından hizmetler kullanılabilir. Bu, içeriği işlemeden önce başlatma mantığını çalıştırmak için yararlı olabilir:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.Services.AddSingleton<WeatherService>();
...

var host = builder.Build();

var weatherService = host.Services.GetRequiredService<WeatherService>();
await weatherService.InitializeWeatherAsync();

await host.RunAsync();

Konak, uygulama için merkezi bir yapılandırma örneği sağlar. Yukarıdaki örnekte, hava durumu hizmetinin URL'si varsayılan yapılandırma kaynağından (örneğin, appsettings.json) öğesine InitializeWeatherAsyncgeçirilir:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.Services.AddSingleton<WeatherService>();
...

var host = builder.Build();

var weatherService = host.Services.GetRequiredService<WeatherService>();
await weatherService.InitializeWeatherAsync(
    host.Configuration["WeatherServiceUrl"]);

await host.RunAsync();

Sunucu tarafı hizmetleri ekleme

Yeni bir uygulama oluşturduktan sonra dosyanın bir bölümünü Program inceleyin:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();

builder değişkeni, hizmet tanımlayıcısı nesnelerinin listesi olan ile bir IServiceCollectionöğesini temsil ederWebApplicationBuilder. Hizmetler, hizmet koleksiyonuna hizmet tanımlayıcıları sağlanarak eklenir. Aşağıdaki örnekte, arabirimi ve somut uygulaması DataAccessile IDataAccess kavramı gösterilmektedir:

builder.Services.AddSingleton<IDataAccess, DataAccess>();

Yeni bir uygulama oluşturduktan sonra içindeki yöntemini Startup.csinceleyinStartup.ConfigureServices:

using Microsoft.Extensions.DependencyInjection;

...

public void ConfigureServices(IServiceCollection services)
{
    ...
}

yöntemineConfigureServices, hizmet tanımlayıcısı nesnelerinin listesi olan bir geçirilirIServiceCollection. Hizmetler, hizmet koleksiyonuna ConfigureServices hizmet tanımlayıcıları sağlanarak yöntemine eklenir. Aşağıdaki örnekte, arabirimi ve somut uygulaması DataAccessile IDataAccess kavramı gösterilmektedir:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IDataAccess, DataAccess>();
}

Ortak hizmetleri kaydetme

Bir veya daha fazla yaygın hizmet için istemci ve sunucu tarafı gerekiyorsa, ortak hizmet kayıtlarını bir yöntem istemci tarafına yerleştirebilir ve her iki projede de hizmetleri kaydetmek için yöntemini çağırabilirsiniz.

İlk olarak, ortak hizmet kayıtlarını ayrı bir yönteme ekleyin. Örneğin, istemci tarafı bir ConfigureCommonServices yöntem oluşturun:

public static void ConfigureCommonServices(IServiceCollection services)
{
    services.Add...;
}

İstemci tarafı Program dosyası için, ortak hizmetleri kaydetmek için çağrısında ConfigureCommonServices bulunun:

var builder = WebAssemblyHostBuilder.CreateDefault(args);

...

ConfigureCommonServices(builder.Services);

Sunucu tarafı Program dosyasında, ortak hizmetleri kaydetmek için çağrısında ConfigureCommonServices bulunun:

var builder = WebApplication.CreateBuilder(args);

...

Client.Program.ConfigureCommonServices(builder.Services);

Bu yaklaşımın bir örneği için bkz . ASP.NET Core Blazor WebAssembly ek güvenlik senaryoları.

Prerendering sırasında başarısız olan istemci tarafı hizmetleri

Bu bölüm yalnızca Web Apps'teki Blazor WebAssembly bileşenleri için geçerlidir.

Blazor Web Apps normalde istemci tarafı WebAssembly bileşenlerini önceden oluşturur. Bir uygulama yalnızca projede .Client kayıtlı gerekli bir hizmetle çalıştırılıyorsa, bir bileşen ön kayıt sırasında gerekli hizmeti kullanmayı denediğinde uygulamanın yürütülmesi aşağıdakine benzer bir çalışma zamanı hatasıyla sonuçlanır:

InvalidOperationException: '{ASSEMBLY}} türündeki {PROPERTY} için bir değer sağlanamaz. Client.Pages. {BILEŞEN ADı}'. '{SERVICE}' türünde kayıtlı hizmet yok.

Bu sorunu çözmek için aşağıdaki yaklaşımlardan birini kullanın:

  • Bileşen hazırlama sırasında kullanılabilir hale getirmek için hizmeti ana projeye kaydedin.
  • Bileşen için prerendering gerekli değilse, ASP.NET Core Blazor işleme modlarındaki yönergeleri izleyerek ön kayıt özelliğini devre dışı bırakın. Bu yaklaşımı benimserseniz, hizmeti ana projeye kaydetmeniz gerekmez.

Daha fazla bilgi için bkz . İstemci tarafı hizmetleri ön kayıt sırasında çözümlenememesi.

Hizmet ömrü

Hizmetler, aşağıdaki tabloda gösterilen yaşam süreleri ile yapılandırılabilir.

Yaşam süresi Açıklama
Scoped

İstemci tarafı şu anda DI kapsamları kavramına sahip değildir. Scoped-registered services, hizmetler gibi Singleton davranır.

Sunucu tarafı geliştirme, http isteklerinde Scoped kullanım ömrünü destekler, ancak istemciye yüklenen bileşenler arasında bağlantı/devre iletileri arasında SignalR yaşam süresi desteklemez. Uygulamanın Razor Sayfalar veya MVC bölümü, kapsamı belirlenmiş hizmetleri normal şekilde ele alır ve sayfalar veya görünümler arasında veya bir sayfadan veya görünümden bir bileşene gezinirken her HTTP isteğinde hizmetleri yeniden oluşturur. Http istekleri aracılığıyla değil, kullanıcının bağlantı hattı üzerinden SignalR sunucuyla iletişimin gerçekleştiği istemcideki bileşenler arasında gezinirken kapsamı belirlenmiş hizmetler yeniden yapılandırılmaz. İstemcideki aşağıdaki bileşen senaryolarında, kapsamlı hizmetler kullanıcı için yeni bir bağlantı hattı oluşturulduğundan yeniden oluşturulur:

  • Kullanıcı tarayıcının penceresini kapatır. Kullanıcı yeni bir pencere açar ve uygulamaya geri döner.
  • Kullanıcı, tarayıcı penceresinde uygulamanın bir sekmesini kapatır. Kullanıcı yeni bir sekme açar ve uygulamaya geri döner.
  • Kullanıcı tarayıcının yeniden yükle/yenile düğmesini seçer.

Sunucu tarafı uygulamalarda kullanıcı durumunu koruma hakkında daha fazla bilgi için bkz . ASP.NET Çekirdek Blazor durum yönetimi.

Singleton DI, hizmetin tek bir örneğini oluşturur. Hizmet Singleton gerektiren tüm bileşenler hizmetin aynı örneğini alır.
Transient Bir bileşen hizmet kapsayıcısından bir Transient hizmet örneği aldığında hizmetin yeni bir örneğini alır.

DI sistemi, ASP.NET Core'daki DI sistemini temel alır. Daha fazla bilgi için, bkz. ASP.NET Core'de bağımlılık ekleme.

Bileşende hizmet isteme

Hizmetleri bileşenlere eklemek için oluşturucu Blazor ekleme ve özellik eklemeyi destekler.

Oluşturucu ekleme

Hizmetler hizmet koleksiyonuna eklendikten sonra, oluşturucu ekleme ile bileşenlere bir veya daha fazla hizmet ekleyin. Aşağıdaki örnek hizmeti ekler NavigationManager .

ConstructorInjection.razor:

@page "/constructor-injection"

<button @onclick="@(() => Navigation.NavigateTo("/counter"))">
    Take me to the Counter component
</button>

ConstructorInjection.razor.cs:

using Microsoft.AspNetCore.Components;

public partial class ConstructorInjection(NavigationManager navigation)
{
    protected NavigationManager Navigation { get; } = navigation;
}

Özellik ekleme

Hizmetler hizmet koleksiyonuna eklendikten sonra, iki parametresi olan yönergesiyle @injectRazor bileşenlere bir veya daha fazla hizmet ekleyin:

  • Tür: Eklenen hizmetin türü.
  • Özellik: Eklenen uygulama hizmetini alan özelliğin adı. özelliği el ile oluşturulmasını gerektirmez. Derleyici özelliği oluşturur.

Daha fazla bilgi için bkz . ASP.NET Core'da görünümlere bağımlılık ekleme.

Farklı hizmetler eklemek için birden çok @inject deyim kullanın.

Aşağıdaki örnekte yönergesinin nasıl kullanılacağı gösterilmektedir @inject . Uygulayan Services.NavigationManager hizmet bileşenin özelliğine Navigationeklenir. Kodda yalnızca soyutlamanın nasıl kullanıldığına NavigationManager dikkat edin.

PropertyInjection.razor:

@page "/property-injection"
@inject NavigationManager Navigation

<button @onclick="@(() => Navigation.NavigateTo("/counter"))">
    Take me to the Counter component
</button>

Dahili olarak, oluşturulan özellik (Navigation) özniteliğini [Inject]kullanır. Genellikle bu öznitelik doğrudan kullanılmaz. Bileşenler için bir temel sınıf gerekiyorsa ve eklenen özellikler de temel sınıf için gerekliyse, özniteliğini el ile ekleyin:[Inject]

using Microsoft.AspNetCore.Components;

public class ComponentBase : IComponent
{
    [Inject]
    protected NavigationManager Navigation { get; set; } = default!;

    ...
}

Not

Eklenen hizmetlerin kullanılabilir olması beklendiğinden, null-forgiving işleci (default!) ile varsayılan değişmez değer .NET 6 veya sonraki sürümlerde atanır. Daha fazla bilgi için bkz . Null atanabilir başvuru türleri (NTS) ve .NET derleyicisi null durum statik analizi.

Temel sınıftan türetilen bileşenlerde @inject yönergesi gerekli değildir. InjectAttribute Temel sınıfın sayısı yeterlidir. Bileşen yalnızca yönergesini @inherits gerektirir. Aşağıdaki örnekte, eklenen tüm hizmetleri CustomComponentBase bileşeni tarafından Demo kullanılabilir:

@page "/demo"
@inherits CustomComponentBase

Hizmetlerde DI kullanma

Karmaşık hizmetler ek hizmetler gerektirebilir. Aşağıdaki örnekte varsayılan DataAccess hizmet gereklidir HttpClient . @inject (veya [Inject] özniteliği) hizmetlerde kullanılamaz. Bunun yerine oluşturucu ekleme kullanılmalıdır. Gerekli hizmetler, hizmetin oluşturucusunun parametreleri eklenerek eklenir. DI hizmeti oluşturduğunda, oluşturucuda gerektirdiği hizmetleri tanır ve uygun şekilde sağlar. Aşağıdaki örnekte, oluşturucu DI aracılığıyla bir HttpClient alır. HttpClient varsayılan bir hizmettir.

using System.Net.Http;

public class DataAccess : IDataAccess
{
    public DataAccess(HttpClient http)
    {
        ...
    }
}

Oluşturucu ekleme önkoşulları:

  • Bağımsız değişkenlerinin tümü DI tarafından yerine getirilebilen bir oluşturucu bulunmalıdır. Varsayılan değerleri belirtirlerse DI tarafından kapsanmayan ek parametrelere izin verilir.
  • İlgili oluşturucu olmalıdır public.
  • Geçerli bir oluşturucu mevcut olmalıdır. Bir belirsizlik durumunda, DI bir özel durum oluşturur.

Anahtarlı hizmetleri bileşenlere ekleme

Blazor özniteliğini kullanarak anahtarlı hizmetler eklemeyi [Inject] destekler. Anahtarlar, bağımlılık ekleme kullanılırken hizmetlerin kaydının ve tüketiminin kapsamını belirlemeye olanak sağlar. InjectAttribute.Key Hizmetin eklenecek anahtarını belirtmek için özelliğini kullanın:

[Inject(Key = "my-service")]
public IMyService MyService { get; set; }

DI kapsamını yönetmek için yardımcı program temel bileşen sınıfları

ASP.NET Core olmayanBlazor uygulamalarda kapsamı belirlenmiş ve geçici hizmetler genellikle geçerli istek kapsamındadır. İstek tamamlandıktan sonra, kapsamlı ve geçici hizmetler DI sistemi tarafından atılır.

Etkileşimli sunucu tarafı Blazor uygulamalarda DI kapsamı, devre süresi boyunca ( SignalR istemci ile sunucu arasındaki bağlantı) sürer ve bu da kapsamı belirlenmiş ve tek kullanımlık geçici hizmetlerin tek bir bileşenin ömründen çok daha uzun süre yaşamasına neden olabilir. Bu nedenle, hizmet ömrünün bileşenin ömrüyle eşleşmesini istiyorsanız, kapsamlı bir hizmeti doğrudan bir bileşene eklemeyin. Uygulamayan IDisposable bir bileşene eklenen geçici hizmetler, bileşen atıldığında çöp toplanır. Ancak, uygulanan IDisposable eklenen geçici hizmetler, devrenin ömrü boyunca DI kapsayıcısı tarafından korunur ve bu da bileşen atıldığında hizmet çöp toplamasını önler ve bellek sızıntısına neden olur. Türüne dayalı kapsamlı hizmetler için alternatif bir yaklaşım bu bölümün OwningComponentBase ilerleyen bölümlerinde açıklanmıştır ve tek kullanımlık geçici hizmetler hiç kullanılmamalıdır. Daha fazla bilgi için bkz . Geçici atılabilir öğeleri Blazor Server çözmek için tasarım (dotnet/aspnetcore #26676).

Bir bağlantı hattı üzerinde çalışmayan istemci tarafı Blazor uygulamalarında bile, kapsamı belirlenmiş bir yaşam süresiyle kaydedilen hizmetler tekil olarak ele alınır, bu nedenle tipik ASP.NET Core uygulamalarında kapsamı belirlenmiş hizmetlerden daha uzun süre yaşarlar. İstemci tarafı atılabilir geçici hizmetler, tek kullanımlık hizmetlere başvurular tutan DI kapsayıcısı uygulamanın kullanım ömrü boyunca devam ettiğinden, hizmetlerin çöp toplamasını önlediğinden eklendikleri bileşenlerden daha uzun süre de yaşar. Uzun süreli tek kullanımlık geçici hizmetler sunucuda daha fazla endişe verici olsa da, istemci hizmeti kayıtları olarak da bu hizmetlerden kaçınılmalıdır. OwningComponentBase Tür kullanımı, hizmet ömrünü denetlemek için istemci tarafı kapsamlı hizmetler için de önerilir ve tek kullanımlık geçici hizmetler hiç kullanılmamalıdır.

Hizmet ömrünü sınırlayan bir yaklaşım, türün OwningComponentBase kullanılmasıdır. OwningComponentBase, bileşenin ComponentBaseömrüne karşılık gelen bir DI kapsamı oluşturan soyut bir türdür. Bu kapsamı kullanarak, bir bileşen kapsamlı bir yaşam süresine sahip hizmetler ekleyebilir ve bileşen kadar uzun süre yaşamalarını sağlayabilir. Bileşen yok edildiğinde, bileşenin kapsamlı hizmet sağlayıcısından gelen hizmetler de atılır. Bu, bir bileşen içinde yeniden kullanılan ancak bileşenler arasında paylaşılmayan hizmetler için yararlı olabilir.

Türün OwningComponentBase iki sürümü kullanılabilir ve sonraki iki bölümde açıklanmıştır:

OwningComponentBase

OwningComponentBase, türünde korumalı ScopedServices bir özelliğe sahip türün ComponentBase soyut, atılabilir bir alt öğesidirIServiceProvider. Sağlayıcı, bileşenin kullanım ömrü kapsamındaki hizmetleri çözümlemek için kullanılabilir.

veya [Inject] özniteliği kullanılarak @inject bileşene eklenen DI hizmetleri, bileşenin kapsamında oluşturulmaz. Bileşenin kapsamını kullanmak için, hizmetler veya GetServiceile kullanılarak ScopedServicesGetRequiredService çözümlenmelidir. Sağlayıcı kullanılarak ScopedServices çözümlenen tüm hizmetlerin bağımlılıkları bileşenin kapsamında sağlanır.

Aşağıdaki örnekte, kapsamı belirlenmiş bir hizmeti doğrudan ekleme ile sunucuda kullanarak ScopedServices bir hizmeti çözümleme arasındaki fark gösterilmektedir. Bir zaman yolculuğu sınıfı için aşağıdaki arabirim ve uygulama, bir değeri tutmak için bir DTDateTime özellik içerir. Uygulama, sınıfın TimeTravel örneği oluşturulurken ayarlamak DT için çağrısında DateTime.Now bulunur.

ITimeTravel.cs:

public interface ITimeTravel
{
    public DateTime DT { get; set; }
}

TimeTravel.cs:

public class TimeTravel : ITimeTravel
{
    public DateTime DT { get; set; } = DateTime.Now;
}

Hizmet, sunucu tarafı Program dosyasında kapsamı belirlenmiş olarak kaydedilir. Sunucu tarafı, kapsamlı hizmetler, devrenin süresine eşit bir yaşam süresine sahiptir.

Program dosyasında:

builder.Services.AddScoped<ITimeTravel, TimeTravel>();

Aşağıdaki TimeTravel bileşeninde:

  • Zaman yolculuğu hizmeti doğrudan olarak TimeTravel1eklenir@inject.
  • Hizmet ayrıca ve GetRequiredServiceTimeTravel2ile ScopedServices ayrı olarak çözümlenir.

TimeTravel.razor:

@page "/time-travel"
@inject ITimeTravel TimeTravel1
@inherits OwningComponentBase

<h1><code>OwningComponentBase</code> Example</h1>

<ul>
    <li>TimeTravel1.DT: @TimeTravel1?.DT</li>
    <li>TimeTravel2.DT: @TimeTravel2?.DT</li>
</ul>

@code {
    private ITimeTravel TimeTravel2 { get; set; } = default!;

    protected override void OnInitialized()
    {
        TimeTravel2 = ScopedServices.GetRequiredService<ITimeTravel>();
    }
}
@page "/time-travel"
@inject ITimeTravel TimeTravel1
@inherits OwningComponentBase

<h1><code>OwningComponentBase</code> Example</h1>

<ul>
    <li>TimeTravel1.DT: @TimeTravel1?.DT</li>
    <li>TimeTravel2.DT: @TimeTravel2?.DT</li>
</ul>

@code {
    private ITimeTravel TimeTravel2 { get; set; } = default!;

    protected override void OnInitialized()
    {
        TimeTravel2 = ScopedServices.GetRequiredService<ITimeTravel>();
    }
}

Başlangıçta bileşene TimeTravel gitmek için, zaman yolculuğu hizmeti bileşen yüklendiğinde iki kez örneklenir ve TimeTravel1TimeTravel2 aynı başlangıç değerine sahiptir:

TimeTravel1.DT: 8/31/2022 2:54:45 PM
TimeTravel2.DT: 8/31/2022 2:54:45 PM

Bileşenden TimeTravel başka bir bileşene ve bileşene TimeTravel geri dönerken:

  • TimeTravel1 , bileşen ilk yüklendiğinde oluşturulan hizmet örneğinin aynısı sağlanır, bu nedenle değeri DT aynı kalır.
  • TimeTravel2 içinde yeni ITimeTravel bir DT değeriyle yeni bir hizmet örneği TimeTravel2 alır.

TimeTravel1.DT: 8/31/2022 2:54:45 PM
TimeTravel2.DT: 8/31/2022 2:54:48 PM

TimeTravel1 kullanıcının bağlantı hattına bağlıdır. Bu bağlantı hattı bozulmadan kalır ve temel bağlantı hattı kaldırılana kadar atılamaz. Örneğin, bağlantısı kesilmiş devre saklama süresi için bağlantı hattı kesilirse hizmet atılır.

Dosyadaki Program kapsamlı hizmet kaydına ve kullanıcının bağlantı hattının uzun ömürlü olmasına rağmen, TimeTravel2 bileşen her başlatıldığında yeni ITimeTravel bir hizmet örneği alır.

OwningComponentBase<TService>

OwningComponentBase<TService>türetilir OwningComponentBase ve kapsamı belirlenmiş DI sağlayıcısından bir örneğini T döndüren bir özellik eklerService. Bu tür, bileşenin kapsamını kullanarak DI kapsayıcısından uygulamanın gerektirdiği tek bir birincil hizmet olduğunda örneği IServiceProvider kullanmadan kapsamlı hizmetlere erişmenin kullanışlı bir yoludur. ScopedServices Özelliği kullanılabilir, böylece uygulama gerekirse diğer türlerdeki hizmetleri alabilir.

@page "/users"
@attribute [Authorize]
@inherits OwningComponentBase<AppDbContext>

<h1>Users (@Service.Users.Count())</h1>

<ul>
    @foreach (var user in Service.Users)
    {
        <li>@user.UserName</li>
    }
</ul>

İstemci tarafı geçici atılabilirleri algılama

Kullanması OwningComponentBasegereken bir uygulamadaki tek kullanımlık geçici hizmetleri algılamak için istemci tarafı Blazor uygulamasına özel kod eklenebilir. Bu yaklaşım, gelecekte uygulamaya eklenen kodun kitaplıklar tarafından eklenen hizmetler de dahil olmak üzere bir veya daha fazla geçici atılabilir hizmet kullandığından endişe ediyorsanız kullanışlıdır. Örnek GitHub deposunda (nasıl indirilir) tanıtım kodu bulunurBlazor.

Örneğin .NET 6 veya sonraki sürümlerinde BlazorSample_WebAssembly aşağıdakileri inceleyin:

  • DetectIncorrectUsagesOfTransientDisposables.cs
  • Services/TransientDisposableService.cs
  • içinde Program.cs:
    • Uygulamanın Services ad alanı, dosyanın (using BlazorSample.Services;) en üstünde sağlanır.
    • DetectIncorrectUsageOfTransients , 'den atandıktan hemen sonra builder çağrılır WebAssemblyHostBuilder.CreateDefault.
    • TransientDisposableService kaydedilir (builder.Services.AddTransient<TransientDisposableService>();).
    • EnableTransientDisposableDetection , uygulamanın (host.EnableTransientDisposableDetection();) işlem hattındaki yerleşik ana bilgisayarda çağrılır.
  • Uygulama, özel durum oluşturmadan hizmeti kaydeder TransientDisposableService . Ancak, içinde TransientService.razor hizmetini çözümlemeye çalışmak, çerçeve bir örneğini TransientDisposableServiceoluşturma girişiminde bulununca bir oluştururInvalidOperationException.

Sunucu tarafı geçici tek kullanımlıkları algılama

Kullanması OwningComponentBasegereken bir uygulamada sunucu tarafı atılabilir geçici hizmetleri algılamak için bir sunucu tarafı Blazor uygulamasına özel kod eklenebilir. Bu yaklaşım, gelecekte uygulamaya eklenen kodun kitaplıklar tarafından eklenen hizmetler de dahil olmak üzere bir veya daha fazla geçici atılabilir hizmet kullandığından endişe ediyorsanız kullanışlıdır. Örnek GitHub deposunda (nasıl indirilir) tanıtım kodu bulunurBlazor.

Örneğin .NET 8 veya sonraki sürümlerinde BlazorSample_BlazorWebApp aşağıdakileri inceleyin:

Örneğin .NET 6 veya .NET 7 sürümlerinde BlazorSample_Server aşağıdakileri inceleyin:

  • DetectIncorrectUsagesOfTransientDisposables.cs
  • Services/TransitiveTransientDisposableDependency.cs:
  • içinde Program.cs:
    • Uygulamanın Services ad alanı, dosyanın (using BlazorSample.Services;) en üstünde sağlanır.
    • DetectIncorrectUsageOfTransients , ana bilgisayar oluşturucusunun (builder.DetectIncorrectUsageOfTransients();) üzerinde çağrılır.
    • Hizmet TransientDependency kayıtlıdır (builder.Services.AddTransient<TransientDependency>();).
    • TransitiveTransientDisposableDependency( için ITransitiveTransientDisposableDependencybuilder.Services.AddTransient<ITransitiveTransientDisposableDependency, TransitiveTransientDisposableDependency>();kaydedilir.
  • Uygulama, özel durum oluşturmadan hizmeti kaydeder TransientDependency . Ancak, içinde TransientService.razor hizmetini çözümlemeye çalışmak, çerçeve bir örneğini TransientDependencyoluşturma girişiminde bulununca bir oluştururInvalidOperationException.

İşleyiciler için IHttpClientFactory/HttpClient geçici hizmet kayıtları

İşleyiciler için IHttpClientFactory/HttpClient geçici hizmet kayıtları önerilir. Uygulama işleyiciler içeriyorsa IHttpClientFactory/HttpClient ve kimlik doğrulaması için destek eklemek için öğesini IRemoteAuthenticationBuilder<TRemoteAuthenticationState,TAccount> kullanıyorsa, istemci tarafı kimlik doğrulaması için aşağıdaki geçici atılabilir öğeler de bulunur ve bu da beklenen ve yoksayılabilir:

Diğer örnekleri IHttpClientFactory/HttpClient de bulunur. Bu örnekler de yoksayılabilir.

Blazor Örnek GitHub deposundaki Blazor örnek uygulamalar (nasıl indirilir) geçici atılabilir öğeleri algılama kodunu gösterir. Ancak örnek uygulamalar işleyiciler içerdiğinden IHttpClientFactory/HttpClient kod devre dışı bırakılır.

Tanıtım kodunu etkinleştirmek ve çalışmasına tanık olmak için:

  • içinde Program.csgeçici tek kullanımlık satırların açıklamasını kaldırın.

  • Bileşenin uygulamanın gezinti kenar çubuğunda görüntülenmesini engelleyen TransientService koşullu denetimi NavLink.razor kaldırın:

    - else if (name != "TransientService")
    + else
    
  • Örnek uygulamayı çalıştırın ve konumundaki /transient-servicebileşene TransientService gidin.

DI'den Entity Framework Core (EF Core) DbContext kullanımı

Daha fazla bilgi için bkz. Entity Framework Core (EF Core) ile ASP.NET CoreBlazor.

Farklı bir DI kapsamından sunucu tarafı Blazor hizmetlerine erişme

Devre etkinliği işleyicileri, kullanılarak oluşturulan kapsamlar gibi diğer bağımlılık eklemeBlazor (DI) kapsamlarından kapsamı belirlenmiş Blazor hizmetlere erişmek için bir yaklaşım sağlar.IHttpClientFactory

.NET 8'de ASP.NET Core yayımlanmadan önce, özel bir temel bileşen türü kullanılarak gereken diğer bağımlılık ekleme kapsamlarından devre kapsamlı hizmetlere erişilir. Bağlantı hattı etkinlik işleyicilerinde, aşağıdaki örnekte gösterildiği gibi özel bir temel bileşen türü gerekli değildir:

public class CircuitServicesAccessor
{
    static readonly AsyncLocal<IServiceProvider> blazorServices = new();

    public IServiceProvider? Services
    {
        get => blazorServices.Value;
        set => blazorServices.Value = value;
    }
}

public class ServicesAccessorCircuitHandler : CircuitHandler
{
    readonly IServiceProvider services;
    readonly CircuitServicesAccessor circuitServicesAccessor;

    public ServicesAccessorCircuitHandler(IServiceProvider services, 
        CircuitServicesAccessor servicesAccessor)
    {
        this.services = services;
        this.circuitServicesAccessor = servicesAccessor;
    }

    public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(
        Func<CircuitInboundActivityContext, Task> next)
    {
        return async context =>
        {
            circuitServicesAccessor.Services = services;
            await next(context);
            circuitServicesAccessor.Services = null;
        };
    }
}

public static class CircuitServicesServiceCollectionExtensions
{
    public static IServiceCollection AddCircuitServicesAccessor(
        this IServiceCollection services)
    {
        services.AddScoped<CircuitServicesAccessor>();
        services.AddScoped<CircuitHandler, ServicesAccessorCircuitHandler>();

        return services;
    }
}

Gereken yere ekleyerek devre kapsamlı hizmetlere CircuitServicesAccessor erişin.

kullanarak bir kurulumdan 'a nasıl erişildiğini AuthenticationStateProvider gösteren bir örnek için bkz. Sunucu tarafı ASP.NET Çekirdek Blazor ek güvenlik senaryoları.DelegatingHandlerIHttpClientFactory

Bir bileşenin farklı bir Razor DI kapsamında kod yürüten zaman uyumsuz yöntemleri çağıracağı zamanlar olabilir. Doğru yaklaşım olmadan, bu DI kapsamlarının ve Microsoft.AspNetCore.Components.Server.ProtectedBrowserStoragegibi IJSRuntime hizmetlerine erişimi Blazoryoktur.

Örneğin, HttpClient kullanılarak IHttpClientFactory oluşturulan örneklerin kendi DI hizmet kapsamı vardır. Sonuç olarak, HttpMessageHandler üzerinde HttpClient yapılandırılan örnekler hizmetleri doğrudan eklemez Blazor .

Geçerli zaman uyumsuz bağlamın depolandığı BlazorIServiceProvider öğesini AsyncLocaltanımlayan bir sınıf BlazorServiceAccessor oluşturun. Bir BlazorServiceAcccessor örnek, hizmetlere erişmek Blazor için farklı bir DI hizmet kapsamından edinilebilir.

BlazorServiceAccessor.cs:

internal sealed class BlazorServiceAccessor
{
    private static readonly AsyncLocal<BlazorServiceHolder> s_currentServiceHolder = new();

    public IServiceProvider? Services
    {
        get => s_currentServiceHolder.Value?.Services;
        set
        {
            if (s_currentServiceHolder.Value is { } holder)
            {
                // Clear the current IServiceProvider trapped in the AsyncLocal.
                holder.Services = null;
            }

            if (value is not null)
            {
                // Use object indirection to hold the IServiceProvider in an AsyncLocal
                // so it can be cleared in all ExecutionContexts when it's cleared.
                s_currentServiceHolder.Value = new() { Services = value };
            }
        }
    }

    private sealed class BlazorServiceHolder
    {
        public IServiceProvider? Services { get; set; }
    }
}

Bir async bileşen yöntemi çağrıldığında değerini BlazorServiceAccessor.Services otomatik olarak ayarlamak için, bileşen koduna Razor üç birincil zaman uyumsuz giriş noktasını yeniden uygulayan özel bir temel bileşen oluşturun:

Aşağıdaki sınıf temel bileşen için uygulamayı gösterir.

CustomComponentBase.cs:

using Microsoft.AspNetCore.Components;

public class CustomComponentBase : ComponentBase, IHandleEvent, IHandleAfterRender
{
    private bool hasCalledOnAfterRender;

    [Inject]
    private IServiceProvider Services { get; set; } = default!;

    [Inject]
    private BlazorServiceAccessor BlazorServiceAccessor { get; set; } = default!;

    public override Task SetParametersAsync(ParameterView parameters)
        => InvokeWithBlazorServiceContext(() => base.SetParametersAsync(parameters));

    Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)
        => InvokeWithBlazorServiceContext(() =>
        {
            var task = callback.InvokeAsync(arg);
            var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion &&
                task.Status != TaskStatus.Canceled;

            StateHasChanged();

            return shouldAwaitTask ?
                CallStateHasChangedOnAsyncCompletion(task) :
                Task.CompletedTask;
        });

    Task IHandleAfterRender.OnAfterRenderAsync()
        => InvokeWithBlazorServiceContext(() =>
        {
            var firstRender = !hasCalledOnAfterRender;
            hasCalledOnAfterRender |= true;

            OnAfterRender(firstRender);

            return OnAfterRenderAsync(firstRender);
        });

    private async Task CallStateHasChangedOnAsyncCompletion(Task task)
    {
        try
        {
            await task;
        }
        catch
        {
            if (task.IsCanceled)
            {
                return;
            }

            throw;
        }

        StateHasChanged();
    }

    private async Task InvokeWithBlazorServiceContext(Func<Task> func)
    {
        try
        {
            BlazorServiceAccessor.Services = Services;
            await func();
        }
        finally
        {
            BlazorServiceAccessor.Services = null;
        }
    }
}

Otomatik olarak genişleten CustomComponentBase tüm bileşenler geçerli Blazor DI kapsamında olarak ayarlanmıştırIServiceProvider.BlazorServiceAccessor.Services

Son olarak, Program dosyasına kapsamlı bir hizmet olarak öğesini ekleyin BlazorServiceAccessor :

builder.Services.AddScoped<BlazorServiceAccessor>();

Son olarak, içinde Startup.ConfigureServicesStartup.csöğesini kapsamlı bir hizmet olarak ekleyin BlazorServiceAccessor :

services.AddScoped<BlazorServiceAccessor>();

Ek kaynaklar