-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Private properties on base class should be probed and exception thrown when marked for injection #893
Comments
Created bug-893 branch. |
Unfortunately, there doesn't seem an easy fix for this issue, because the Reflection functionality required to implement this, are not available in .NET Standard 1.0 and 1.3. In order to explain why this is difficult, I first have to set the requirements:
There are two ways to retrieve a type's properties:
Get all properties using With The problem now starts with finding out which base-type properties should be filtered out, because they are already included in the list. The only reliable way of doing this is by calling Perhaps it's still possible to find out, but I'm currently clueless. Have no idea how to do this. There are several workarounds, but I'm not happy with either of them:
|
After a long discussion with @TheBigRic, we came to the conclusion that not injecting private properties is actually good thing, because:
Unfortunately, compared to static and read-only properties, Simple Injector currently skips those properties when probing the custom Instead, Simple Injector should even prope the This last, however, still seems impossible to achieve while we depend on .NET Standard 1.3. I, therefore, move this issue to the Simple Injector v6 milestone. In v6 we might remove (not sure yet) the .NET Standard 1.0 and 1.3 dependency. |
While I would normally agree that private properties would be better replaced by decoration (I am not familiar with the interception pattern). I feel like Blazor would be an exception that proves the rule here. I could be missing something, but it seems like inheritance is all you have in Blazor components. You have no other way to inject dependencies into a class except property injection and it seems reasonable that sometimes you would want those dependencies to be hidden away from inheriting classes? I can see this being the right approach for Simple Injector as a whole, but for Blazor in particular I would need some convincing on this. |
It certainly seems that there are currently some limitations on Blazor that make interception (either through middleware, decorators, or dynamic interception) hard (if not impossible). I had discussions with the Blazor team about this.
In order to be able convince you (or agree with you), I'm interested to learn what dependencies you have on the base class and how you would intend to use them. |
I'll give two examples, both in Blazor because that is what I have been working most in as of late.
private IModalService _modal { get; set; }
protected async Task<bool> ShowConfirmBox(
string title, string message, string ok = "Ok", string cancel = "Cancel")
{
ModalParameters parameters = new ModalParameters();
parameters.Add(nameof(ConfirmBox.Message), message);
parameters.Add(nameof(ConfirmBox.OK), ok);
parameters.Add(nameof(ConfirmBox.Cancel), cancel);
var modal = _modal.Show<ConfirmBox>(title, parameters);
var choice = await modal.Result;
return !choice.Cancelled;
} While I can imagine one might argue that this could be pulled out into a separate class and injected into the child class via a private property, to me it is so often used that I prefer not to have to inject it every time I need it. private IMapper _mapper { get; set; }
protected T Map<T>(object source)
{
return _mapper.Map<T>(source);
} The inheriting classes don't need access to the IMapper instance so why not make it private? |
The first example can be rewritten to an extension method on And I would argue that it's better to inject In case you your Blazor components get too many dependencies, it might get cumbersome, but in that case I would argue that those components become too big. I see no justification for big components, especially because Blazor makes it easy to compose Blazor components from other components. |
I didn't think of the extension method. That is a better solution for that scenario. Fair enough for the second example. Ok, carry on 🐱👤I can't think of any other examples at this point. |
@thepigeonfighter, thank you for your response. Do note that, as I noted in the above analysis, even if I wished to add support for private properties, it's not possible ATM (or -at least- not in the core library). I added a documentation example, though, that demonstrates how to work around this issue. It might be possible to add this behavior in a future Blazor-integration package. I bring this up, because I just noticed that the property-injection behavior of Blazor itself, actually does inject into private properties of base classes. Not implementing this might, therefore, cause incompatibility issues when developers migrate from MS.DI to Simple Injector (even though I still think base classes shouldn't have dependencies). This behavior is implemented inside the |
Code to demonstrate the problem:
The test fails, while the expected behavior is for the property to get injected, because:
Fixing this issue, however, should be considered a breaking change, because Simple Injector will start calling
SelectProperty
on properties that were previously skipped.The text was updated successfully, but these errors were encountered: