Transient dependency example (#23490)
parent
0a16f190d0
commit
f00589b442
|
@ -179,9 +179,13 @@ Prerequisites for constructor injection:
|
|||
|
||||
In ASP.NET Core apps, scoped services are typically scoped to the current request. After the request completes, any scoped or transient services are disposed by the DI system. In Blazor Server apps, the request scope lasts for the duration of the client connection, which can result in transient and scoped services living much longer than expected. In Blazor WebAssembly apps, services registered with a scoped lifetime are treated as singletons, so they live longer than scoped services in typical ASP.NET Core apps.
|
||||
|
||||
<!--
|
||||
|
||||
> [!NOTE]
|
||||
> To detect disposable transient services in an app, see the [Detect transient disposables](#detect-transient-disposables) section.
|
||||
|
||||
-->
|
||||
|
||||
An approach that limits a service lifetime in Blazor apps is use of the <xref:Microsoft.AspNetCore.Components.OwningComponentBase> type. <xref:Microsoft.AspNetCore.Components.OwningComponentBase> is an abstract type derived from <xref:Microsoft.AspNetCore.Components.ComponentBase> that creates a DI scope corresponding to the lifetime of the component. Using this scope, it's possible to use DI services with a scoped lifetime and have them live as long as the component. When the component is destroyed, services from the component's scoped service provider are disposed as well. This can be useful for services that:
|
||||
|
||||
* Should be reused within a component, as the transient lifetime is inappropriate.
|
||||
|
@ -216,9 +220,11 @@ Two versions of the <xref:Microsoft.AspNetCore.Components.OwningComponentBase> t
|
|||
|
||||
For more information, see <xref:blazor/blazor-server-ef-core>.
|
||||
|
||||
<!--
|
||||
|
||||
## Detect transient disposables
|
||||
|
||||
The following examples show how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
The following example shows how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
|
||||
::: zone pivot="webassembly"
|
||||
|
||||
|
@ -226,25 +232,6 @@ The following examples show how to detect disposable transient services in an ap
|
|||
|
||||
[!code-csharp[](~/blazor/samples/6.0/BlazorSample_WebAssembly/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs)]
|
||||
|
||||
The `TransientDisposable` in the following example is detected (`Program.cs`):
|
||||
|
||||
```csharp
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.DetectIncorrectUsageOfTransients();
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
|
||||
builder.Services.AddTransient<TransientDisposable>();
|
||||
builder.Services.AddScoped(sp =>
|
||||
new HttpClient
|
||||
{
|
||||
BaseAddress = new(builder.HostEnvironment.BaseAddress)
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
host.EnableTransientDisposableDetection();
|
||||
await host.RunAsync();
|
||||
```
|
||||
|
||||
`TransientDisposable.cs`:
|
||||
|
||||
```csharp
|
||||
|
@ -254,6 +241,32 @@ public class TransientDisposable : IDisposable
|
|||
}
|
||||
```
|
||||
|
||||
The `TransientDisposable` in the following example is detected.
|
||||
|
||||
`Program.cs`:
|
||||
|
||||
```csharp
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using BlazorWebAssemblyTransientDisposable;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.DetectIncorrectUsageOfTransients();
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
builder.Services.AddTransient<TransientDisposable>();
|
||||
builder.Services.AddScoped(sp =>
|
||||
new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
host.EnableTransientDisposableDetection();
|
||||
await host.RunAsync();
|
||||
```
|
||||
|
||||
::: zone-end
|
||||
|
||||
::: zone pivot="server"
|
||||
|
@ -262,12 +275,6 @@ public class TransientDisposable : IDisposable
|
|||
|
||||
[!code-csharp[](~/blazor/samples/6.0/BlazorSample_Server/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs)]
|
||||
|
||||
In `Program.cs`:
|
||||
|
||||
```csharp
|
||||
app.DetectIncorrectUsageOfTransients();
|
||||
```
|
||||
|
||||
`TransitiveTransientDisposableDependency.cs`:
|
||||
|
||||
```csharp
|
||||
|
@ -295,34 +302,43 @@ public class TransientDependency
|
|||
}
|
||||
```
|
||||
|
||||
The `TransientDependency` in the following example is detected (`Program.cs`):
|
||||
The `TransientDependency` in the following example is detected.
|
||||
|
||||
In `Program.cs`:
|
||||
|
||||
```csharp
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddSingleton<WeatherForecastService>();
|
||||
...
|
||||
|
||||
builder.Services.AddTransient<TransientDependency>();
|
||||
builder.Services.AddTransient<ITransitiveTransientDisposableDependency,
|
||||
TransitiveTransientDisposableDependency>();
|
||||
|
||||
...
|
||||
|
||||
app.DetectIncorrectUsageOfTransients();
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
::: zone-end
|
||||
|
||||
The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an <xref:System.InvalidOperationException>, as the following example shows.
|
||||
|
||||
`Pages/TransientDisposable.razor`:
|
||||
`Pages/TransientExample.razor`:
|
||||
|
||||
```razor
|
||||
@page "/transient-disposable"
|
||||
@page "/transient-example"
|
||||
@inject TransientDisposable TransientDisposable
|
||||
|
||||
<h1>Transient Disposable Detection</h1>
|
||||
```
|
||||
|
||||
Navigate to the `TransientDisposable` component at `/transient-disposable` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
Navigate to the `TransientExample` component at `/transient-example` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
|
||||
> System.InvalidOperationException: Trying to resolve transient disposable service TransientDisposable in the wrong scope. Use an 'OwningComponentBase\<T>' component base class for the service 'T' you are trying to resolve.
|
||||
|
||||
-->
|
||||
|
||||
## Additional resources
|
||||
|
||||
* <xref:fundamentals/dependency-injection>
|
||||
|
@ -559,7 +575,7 @@ For more information, see <xref:blazor/blazor-server-ef-core>.
|
|||
|
||||
## Detect transient disposables
|
||||
|
||||
The following examples show how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
The following example shows how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
|
||||
::: zone pivot="webassembly"
|
||||
|
||||
|
@ -664,16 +680,16 @@ public class TransientDependency
|
|||
|
||||
The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an <xref:System.InvalidOperationException>, as the following example shows.
|
||||
|
||||
`Pages/TransientDisposable.razor`:
|
||||
`Pages/TransientExample.razor`:
|
||||
|
||||
```razor
|
||||
@page "/transient-disposable"
|
||||
@page "/transient-example"
|
||||
@inject TransientDisposable TransientDisposable
|
||||
|
||||
<h1>Transient Disposable Detection</h1>
|
||||
```
|
||||
|
||||
Navigate to the `TransientDisposable` component at `/transient-disposable` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
Navigate to the `TransientExample` component at `/transient-example` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
|
||||
> System.InvalidOperationException: Trying to resolve transient disposable service TransientDisposable in the wrong scope. Use an 'OwningComponentBase\<T>' component base class for the service 'T' you are trying to resolve.
|
||||
|
||||
|
@ -913,7 +929,7 @@ For more information, see <xref:blazor/blazor-server-ef-core>.
|
|||
|
||||
## Detect transient disposables
|
||||
|
||||
The following examples show how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
The following example shows how to detect disposable transient services in an app that should use <xref:Microsoft.AspNetCore.Components.OwningComponentBase>. For more information, see the [Utility base component classes to manage a DI scope](#utility-base-component-classes-to-manage-a-di-scope) section.
|
||||
|
||||
::: zone pivot="webassembly"
|
||||
|
||||
|
@ -1018,16 +1034,16 @@ public class TransientDependency
|
|||
|
||||
The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an <xref:System.InvalidOperationException>, as the following example shows.
|
||||
|
||||
`Pages/TransientDisposable.razor`:
|
||||
`Pages/TransientExample.razor`:
|
||||
|
||||
```razor
|
||||
@page "/transient-disposable"
|
||||
@page "/transient-example"
|
||||
@inject TransientDisposable TransientDisposable
|
||||
|
||||
<h1>Transient Disposable Detection</h1>
|
||||
```
|
||||
|
||||
Navigate to the `TransientDisposable` component at `/transient-disposable` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
Navigate to the `TransientExample` component at `/transient-example` and an <xref:System.InvalidOperationException> is thrown when the framework attempts to construct an instance of `TransientDisposable`:
|
||||
|
||||
> System.InvalidOperationException: Trying to resolve transient disposable service TransientDisposable in the wrong scope. Use an 'OwningComponentBase\<T>' component base class for the service 'T' you are trying to resolve.
|
||||
|
||||
|
|
Loading…
Reference in New Issue