-
Notifications
You must be signed in to change notification settings - Fork 779
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
Fix dependency injection issue #339
Conversation
Thanks for the pull request. Can you clarify the issue that this pull request solves? Currently the container will resolve single registrations when |
Some containers (like Simple Injector) do not create new instances implicitly when GetAllInstances is called and instead return empty collection. With this fix Caliburn.Micro will also try to get an instance via GetInstance |
I think the question here is, when you expect a single instance, which you do, hence this call: var view = IoC.GetAllInstances(viewType).FirstOrDefault() as UIElement; why would you call In other words I would recommend that the call is being changed to: var view = IoC.GetInstance(viewType, null); |
I'm inclined to agree @TheBigRic , this code predates me and i can't think of a good reason why I'd like to switch this over, but depending on the container a developer is using this could be a breaking change and will be have to held off to a |
I think my solution can be used until 4.0.0 is released. It relies on current behavior, but tries to retrieve an instance the right way if |
I agree with both of you. It is a breaking change an thus should be in a major version release. The fix in this pull request is very unlikely to break anybody's application I guess, although there are probably implementations depending on this exact implementation. |
Hmm, it seems this might broke a lot more than just MEF. I used Autofac and this also throws an Exception because of trying to resolve an unregistered type now. Can be solved by:
|
Yeah, it would affect any container that throws an exception when unable to resolve a dependency (not sure of the full list here). Apologies again. |
Same with Ninject. Checking for service type assignable to UIElement did the trick. |
This change also broke the Caliburn.Micro.Start that uses the SimpleContainer and all the apps that based their implementations on this one to integrate another container. From Caliburn.Micro.Start 3.0.2, AppBootstrapper.cs
I've always assumed that if the service is not found it should throw, and from several implementations I've seen out there I'm not alone. What should be the correct behavior, to throw or return null? By the way, what is the point of calling IoC.GetInstance after the IoC.GetAllInstances returning an empty collection? |
Just run unexpectly into this issue when upgrading 3.0.1 to 3.0.2... For SimpleContainer, this does the trick but is it right?
|
@ZoolWay that's pretty much right, I'm debating reverting this one till 4.0.0 since it's become more of a breaking change than expected. |
Turns out this one caught me out as well. Moving towards using some external modules with views and viewmodels. Spent the entire day pulling my hair out trying to work out why it just wouldn't find any instances of my views anymore. Turns out at some point I absent mindedly upgraded to 3.0.2 (Because the new DLL used the latest available on NUGET, so i upgraded the main app to match) Thankfully the above posted solutions solved my problems. |
This bit me as well and wasted hours of my time. I started a new project and used my normal bootstrapper code and then kept getting errors saying couldn't find views. Figured I was missing something stupid on my part and ended up putting Export attributes on my view's as a quick fix so I could keep working until I figured out what happened. Finally thought of downgrading the package and then after more digging found this pull request through the release notes. Painful... I would vote for reverting this to help others save their sanity... |
I've reverted this out in Apologies to all. |
Surprisingly I never encountered this issue. Is it specific to certain ioc
containers? Note: I don't register the views, at least to the best of my
knowledge.
…On 9 Jan 2017 11:37, "Nigel Sampson" ***@***.***> wrote:
I've revert this out in 3.0.3, it shouldn't have been included in 3.0.2.
It may be included in 4.0.0
Apologies to all.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#339 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHbkI4l3BqwxIDef2p-sQRviod_a9v6uks5rQf_CgaJpZM4I0zOO>
.
|
It's specific to containers that throw exceptions on failure to resolve the dependency such as |
If I understand correctly 4.0 will resolve views solely based on .GetInstance? Which I still think of as the only sensible thing to do here. Notice that while Simple Injector started with throwing exceptions instead of retuning null for instances which can't be created, almost every container out there is now doing this. And this is offcourse a pretty sane approach. We as developers want things to fail fast with clear exceptions and stack traces instead of tricky and hard to debug issues with In the dev branch for 4.0.0 I still see the same code, which uses .GetAllInstances. This is an open issue or are there any compelling reasons to leave this as is? I'm happy to send in a PR. |
It would be great for this to be fixed. I hate having to use those ugly workarounds in bootsrapper to get SimpleInjector (and it seems like plenty other IoC containers these days) working. |
After the hiccups when this first rolled out, I'm a little hesitant to do it again. Especially as you said more frameworks throwing on dependency resolution failure. Are there many people out there using the container for view construction? I almost feel like I want to go the other way and remove it if it's not being used. |
Why do you consider this a problem? If a view can't be created by a DI container, how would caliburn be able to create the view. So in the end there will be an exception anyway, unless you consider showing a default view with a single Textblock, label or whatever no exception? If you as a programmer made a mistake, also known as a bug, shouldn't it be fair to throw an exception? I certainly want that!! But apart from the exception part. Caliburn clearly expects a single view returned from the call to With SimpleInjector for exampling you have to make a pretty nasty workaround to let the container resolve a view because SimpleInjector seperates registrations for collections from other registrations Again I'm happy to provide a PR with my solution and I'm open for everybody seeing problems in this approach. |
And even if that is a problem, a backwards compatibility option could be added. SimpleInjector had something to this effect (before they decided throwing an exception is always the right way to proceed): |
Any time a developer wants to integrate as DI container that has this behavior there's additional work to be done that's not immediately apparent.
Most of the time (that I've seen) views aren't registered with the container, which means Caliburn falls back to
This is pretty much what happens. In summary, I've yet to see anyone use dependency injection into views themselves and it feels like even trying to resolve the view out of the container adds a layer of complication that isn't required. Especially when in order to make it "correct" adds extra friction for developers who don't want it. The extension point of I'm happy to see a PR around a proposed solution though. |
I think you definitively has seen more far more examples as I have, so you would know much better. However, this is a far greater breaking change than the one I'm suggesting. The current design is IMO flawed in 2 ways:
About DI container becoming more strict: I'm not saying other DI maintainers are following Simple Injector, this move from failing silent or at a later point in time towards throwing exceptions I see in the complete industry. And this helps us all in creating better software. So I think users should become more and more accustomed to the fact that a library or framework could throw an exception. While the builders of these tools should invest in throwing exceptions with clear exception messages. You'll see a PR in the next days. |
Definitely not going to argue the current design is flawed. especially for reason 1. I haven't seen many DI containers inject null's when not resolving dependencies, they tend to return null if they can't resolve the entire tree. My thought process is going something like this. There's two solutions we can head down:
Sadly I don't have numbers to back my gut feeling up, but I feel that the amount of developers affected by 2. is smaller than 1. A middle ground would be a setting on If you do still want to create a PR for further discussion (always happy for that) then I'd probably target the |
When I'm trying to build the project I get this error.
What I find suspoious here is that is for the Xamarin.IOS version of the project while the compiler is searching in the MonoAndroid10 object directory. The new csproj format rocks, when it works :-) Any ideas? |
Yeah the new format is looking promising, I'll have to have a play at home with a clean build to see if I can recreate the above issue. If you're truly blocked create the PR against |
@TheBigRic I managed to recreate the compile error on my machine and pushed a fix, do you mind testing? |
Yep, that worked! Good work finding that! Seems still a blackbox-a-like thingy this new csproj. The documentation from ms is not complete and to much spread out over different site/blogs/forums, etc. if you ask me. Anyways, will work on the PR tomorrow! |
I think it's a good idea to try to retrieve single instance when GetAllInstances returns empty collection.
See simpleinjector/SimpleInjector#251 (comment)