Optional dependency @inject for Blazor
Is your feature request related to a problem? Please describe.
In some situations, services can be optional. For regular classes we can write
public class Foo
{
public Foo(IService service = null) {} // optional dependency on IService
}
For @inject and [Inject], there's no such equivalence.
Describe the solution you'd like
I'd love to see a parameter to the Inject attribute that allows to mark a dependency as optional, e.g. [Inject(Optional = true)]. The @inject directive could be extended to make @inject IService Service = null valid and equivalent with [Inject(Optional = true)] IService Service {get;set;} which (as far as I can see) would not break any existing code as it would be a syntax error so far.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Honestly, it would be nicer to be able to do "normal" constructor injection using codebehind mycomponent.razor.cs classes. Then you can have optional injection if you need it without faffing around with @ directives.
Honestly, I don't mind which way it works, as long as I can make dependencies optional: whether allowing DI constructors or adding support for optional dependencies with directives has the smaller impact on the framework, I can't say.
let's just say, parameter injection is nasty. And the @ directive is really just parameter injection in disguise. I'm not saying do away with it, some people like code and markup in the same file and who am I to judge? But where you have a complex requirement, there's a real benefit to going down the standard path.
@stefanloerwald:
meanwhile, can you use this?
@inject IServiceProvider ServiceProvider
@code
{
IService _service;
protected override void OnInitialized()
{
_service = ServiceProvider.GetService<IService>();
}
}
Thank you @Liero for the suggestion. That code absolutely works and is a nice workaround. I still hope the feature will be added directly into Blazor.
Any update on this?
Thanks for contacting us.
We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
I would also appreciate this. One use case where it makes sense: Imagine you are developing a reusable Blazor component. Now you want to inject IStringLocalizer<> in case the app support multilang. But if IStringLocalizer<> is not registered as a service, it is safe to assume the app is single language and should display all messages in a default language. Right now there is no clean way to support both scenarios, as injecting IStringLocalizer will throw an error saying the service is not registered.
I also feel this would be a useful feature. There are times I want to abstract a component out and allow the user to pass their own handler but I don't want to make them specify one every time and I don't want them to have to register a service for it so this feature would allow for a default one to be specified.
Another use case we've found for it:
We have a custom validation component. Currently it uses DI to get the correct validator. We'd like to make it so that the user can provide their own validator in certain cases. To make it work as things currently are, we need to add a nullable validator property and then default back to DI if it's null or not and we need to babysit the property and make sure that our real validator is updated whenever the property changes.
This would also be very useful for prerendering. I've got a scenario where I have a service which does javascript interop, but on the server it doesn't do anything. I currently have to write the following to make prerendering work:
public interface IMyService
{
ValueTask DoSomething();
}
public class MyService : IMyService
{
public ValueTask DoSomething()
{
// Do something
}
}
public class MyVoidService : IMyService
{
public ValueTask DoSomething() => ValueTask.CompletedTask;
}
Having optional DI would solve the problem of having to write services just to eat the errors
Thanks for contacting us.
We're moving this issue to the
.NET 8 Planningmilestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Can this be moved into .NET 9 planning, or would it be best to place into .NET 10 planning at this point?
@StefanJanssen95
This would also be very useful for prerendering. I've got a scenario where I have a service which does javascript interop, but on the server it doesn't do anything. Having optional DI would solve the problem of having to write services just to eat the errors
You don't have to write dummy service, see https://github.com/dotnet/razor/issues/7653#issuecomment-1295644712
@danroth27,
This looks like a great new feature. Would it be possible to do something such as the following to make injection optional?
public partial class ConstructorInjection(NavigationManager? navigation = null)
{
}
This looks like a great new feature. Would it be possible to do something such as the following to make injection optional?
public partial class ConstructorInjection(NavigationManager? navigation = null) { }
@thirstyape Yup, exactly. You can use the new constructor injection support to make injected services optional.
This looks like a great new feature. Would it be possible to do something such as the following to make injection optional? public partial class ConstructorInjection(NavigationManager? navigation = null) { }
@thirstyape Yup, exactly. You can use the new constructor injection support to make injected services optional.
I am not exactly sure, but I think NavigationManager? navigation = null is not working because the type is not and cannot be registered as nullable type in DI container. I have tried this approach in my application and the parameter is always null. 🤔