From 4f6abfb2b33722fead246af3c8bfbd2d88780902 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 8 Oct 2021 07:11:26 -0500 Subject: [PATCH] Transient dependency example (2) --- .../fundamentals/dependency-injection.md | 90 ++++++++++++------- ...ctIncorrectUsagesOfTransientDisposables.cs | 21 ++++- ...ctIncorrectUsagesOfTransientDisposables.cs | 15 +++- 3 files changed, 91 insertions(+), 35 deletions(-) diff --git a/aspnetcore/blazor/fundamentals/dependency-injection.md b/aspnetcore/blazor/fundamentals/dependency-injection.md index 1566d5b0b69c..bf135bca751d 100644 --- a/aspnetcore/blazor/fundamentals/dependency-injection.md +++ b/aspnetcore/blazor/fundamentals/dependency-injection.md @@ -179,13 +179,9 @@ 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. - - An approach that limits a service lifetime in Blazor apps is use of the type. is an abstract type derived from 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. @@ -220,8 +216,6 @@ Two versions of the t For more information, see . - +::: zone-end ## Additional resources @@ -613,6 +613,21 @@ public class TransientDisposable : IDisposable } ``` +The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an , as the following example shows. + +`Pages/TransientExample.razor`: + +```razor +@page "/transient-example" +@inject TransientDisposable TransientDisposable + +

Transient Disposable Detection

+``` + +Navigate to the `TransientExample` component at `/transient-example` and an 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\' component base class for the service 'T' you are trying to resolve. + ::: zone-end ::: zone pivot="server" @@ -676,22 +691,22 @@ public class TransientDependency } ``` -::: zone-end - The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an , as the following example shows. `Pages/TransientExample.razor`: ```razor @page "/transient-example" -@inject TransientDisposable TransientDisposable +@inject TransientDependency TransientDependency

Transient Disposable Detection

``` -Navigate to the `TransientExample` component at `/transient-example` and an is thrown when the framework attempts to construct an instance of `TransientDisposable`: +Navigate to the `TransientExample` component at `/transient-example` and an is thrown when the framework attempts to construct an instance of `TransientDependency`: -> System.InvalidOperationException: Trying to resolve transient disposable service TransientDisposable in the wrong scope. Use an 'OwningComponentBase\' component base class for the service 'T' you are trying to resolve. +> System.InvalidOperationException: Trying to resolve transient disposable service TransientDependency in the wrong scope. Use an 'OwningComponentBase\' component base class for the service 'T' you are trying to resolve. + +::: zone-end ## Additional resources @@ -967,6 +982,21 @@ public class TransientDisposable : IDisposable } ``` +The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an , as the following example shows. + +`Pages/TransientExample.razor`: + +```razor +@page "/transient-example" +@inject TransientDisposable TransientDisposable + +

Transient Disposable Detection

+``` + +Navigate to the `TransientExample` component at `/transient-example` and an 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\' component base class for the service 'T' you are trying to resolve. + ::: zone-end ::: zone pivot="server" @@ -1030,22 +1060,22 @@ public class TransientDependency } ``` -::: zone-end - The app can register transient disposables without throwing an exception. However, attempting to resolve a transient disposable results in an , as the following example shows. `Pages/TransientExample.razor`: ```razor @page "/transient-example" -@inject TransientDisposable TransientDisposable +@inject TransientDependency TransientDependency

Transient Disposable Detection

``` -Navigate to the `TransientExample` component at `/transient-example` and an is thrown when the framework attempts to construct an instance of `TransientDisposable`: +Navigate to the `TransientExample` component at `/transient-example` and an is thrown when the framework attempts to construct an instance of `TransientDependency`: -> System.InvalidOperationException: Trying to resolve transient disposable service TransientDisposable in the wrong scope. Use an 'OwningComponentBase\' component base class for the service 'T' you are trying to resolve. +> System.InvalidOperationException: Trying to resolve transient disposable service TransientDependency in the wrong scope. Use an 'OwningComponentBase\' component base class for the service 'T' you are trying to resolve. + +::: zone-end ## Additional resources diff --git a/aspnetcore/blazor/samples/6.0/BlazorSample_Server/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs b/aspnetcore/blazor/samples/6.0/BlazorSample_Server/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs index 6c0c12808dcd..ebcf296d7e2f 100644 --- a/aspnetcore/blazor/samples/6.0/BlazorSample_Server/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs +++ b/aspnetcore/blazor/samples/6.0/BlazorSample_Server/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs @@ -11,10 +11,10 @@ namespace Microsoft.Extensions.DependencyInjection public static class WebHostBuilderTransientDisposableExtensions { - public static IHostBuilder DetectIncorrectUsageOfTransients( - this IHostBuilder builder) + public static WebApplicationBuilder DetectIncorrectUsageOfTransients( + this WebApplicationBuilder builder) { - builder + builder.Host .UseServiceProviderFactory( new DetectIncorrectUsageOfTransientDisposablesServiceFactory()) .ConfigureServices( @@ -81,6 +81,13 @@ private ServiceDescriptor CreatePatchedFactoryDescriptor( (sp) => { var originalFactory = original.ImplementationFactory; + + if (originalFactory is null) + { + throw new InvalidOperationException( + "originalFactory is null."); + } + var originalResult = originalFactory(sp); var throwOnTransientDisposable = @@ -114,12 +121,18 @@ private ServiceDescriptor CreatePatchedDescriptor( { throw new InvalidOperationException("Trying to resolve " + "transient disposable service " + - $"{original.ImplementationType.Name} in the wrong " + + $"{original.ImplementationType?.Name} in the wrong " + "scope. Use an 'OwningComponentBase' component " + "base class for the service 'T' you are trying to " + "resolve."); } + if (original.ImplementationType is null) + { + throw new InvalidOperationException( + "ImplementationType is null."); + } + return ActivatorUtilities.CreateInstance(sp, original.ImplementationType); }, diff --git a/aspnetcore/blazor/samples/6.0/BlazorSample_WebAssembly/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs b/aspnetcore/blazor/samples/6.0/BlazorSample_WebAssembly/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs index b7fd4d935cff..eb2ba210664e 100644 --- a/aspnetcore/blazor/samples/6.0/BlazorSample_WebAssembly/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs +++ b/aspnetcore/blazor/samples/6.0/BlazorSample_WebAssembly/dependency-injection/DetectIncorrectUsagesOfTransientDisposables.cs @@ -76,6 +76,13 @@ private ServiceDescriptor CreatePatchedFactoryDescriptor( (sp) => { var originalFactory = original.ImplementationFactory; + + if (originalFactory is null) + { + throw new InvalidOperationException( + "originalFactory is null."); + } + var originalResult = originalFactory(sp); var throwOnTransientDisposable = @@ -108,11 +115,17 @@ private ServiceDescriptor CreatePatchedDescriptor(ServiceDescriptor original) { throw new InvalidOperationException("Trying to resolve " + "transient disposable service " + - $"{original.ImplementationType.Name} in the wrong " + + $"{original.ImplementationType?.Name} in the wrong " + "scope. Use an 'OwningComponentBase' component base " + "class for the service 'T' you are trying to resolve."); } + if (original.ImplementationType is null) + { + throw new InvalidOperationException( + "ImplementationType is null."); + } + return ActivatorUtilities.CreateInstance(sp, original.ImplementationType); },