acmoune
acmoune

Reputation: 3423

Is it possible to automatically create a dependency injection scope matching the lifetime of a Blazor component?

I am wondering if there is something similar to this in Blazor:

@injectScoped IMyService Service

So the injected instance will be created when the component is created and destroyed when the component is destroyed.

Any child component using the same @injectScoped directive will receive the parent's instance, not the singleton (global) one created at the root.

I am still searching for how to achieve that in a Blazor Webassembly app.

Upvotes: 0

Views: 491

Answers (2)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30310

Good question.

There's a problem in the Service Container implementation used by Blazor. It was designed for server-side rendering. Scoped services match the scope of the page/Http request. In Blazor that represents the SPA session. There's no matching scope for a component/page. OwningComponentBase was designed to fit this need, but it's useless in many situations - I explain why further down.

Your options depend on the nature of the service.

No IDisposable/IAsyncDisposable on Service

If your Service doesn't implement IDisposable/IAsyncDisposable you can scope it as Transient and then cascade it from the top level page/form.

IDisposable/IAsyncDisposable on Service

If your Service implements IDisposable/IAsyncDisposable you need to use ActivatorUtilities to create an instance of the service/object with it's dependancies populated from the service container. This ensures the service container doesn't retain any references to the instance. You cascade this as above. Important - You are responsible for the disposal.

Neither of these are perfect. Cascading an object causes constant Render Tree Cascades: it's an object and the Render has no way of detecting changes.

OwningComponentBase

Any Scoped services that your service depends on are created in the same container: it is after all just a Scoped container. Take AuthenticationService. The instance in the SPA scoped container is the one your service needs, but instead it gets a new one with no user information. The same applies to Notification services, the NavigationManager and many others. It's useless, except in very specific circumstances.

My personal current solution is a ComponentServiceProvider service that creates and manages service instances for the component. It's too lengthy to cover here in detail. There's a repo here: https://github.com/ShaunCurtis/Blazr.ComponentServiceProvider along with a more detailed discussion of the above.

Upvotes: 2

Brian Parker
Brian Parker

Reputation: 14613

OwningComponentBase or OwningComponentBase<>

@inherits OwningComponentBase<SomeService>
<h3>SomeComponent</h3>

@code {
    SomeService myService => base.Service;
}

Docs

Upvotes: 1

Related Questions