Skip to content
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

Update Splat.Autofac to work with Autofac 5.0 #465

Closed
ronaldvdv opened this issue Feb 3, 2020 · 20 comments
Closed

Update Splat.Autofac to work with Autofac 5.0 #465

ronaldvdv opened this issue Feb 3, 2020 · 20 comments

Comments

@ronaldvdv
Copy link

Describe the bug
Starting with Autofac 5.0, containers are mutable. See corresponding pull request and release notes . This gives startup errors when using Splat.Autofac.

Steps To Reproduce
Provide the steps to reproduce the behavior:

  • Install Splat.Autofac 9.3 and Autofac 5.0.0 packages
  • In your startup code, call the IContainer.UseAutofacDependencyResolver() extension method.
  • When running your application, this gives an exception: Method not found: 'Void Autofac.ContainerBuilder.Update(Autofac.Core.IComponentRegistry)'.

Environment(please complete the following information):

  • OS: Windows 10
  • Version: Autofac 5.0.0, Splat.Autofac 9.3
@glennawatson
Copy link
Contributor

Thanks for the report

This is related to #463

@RLittlesII RLittlesII changed the title [BUG] Splat.Autofac broken with Autofac 5.0 Update Splat.Autofac to work with Autofac 5.0 Feb 19, 2020
@RLittlesII
Copy link
Member

Changing this to a feature request. Autofac has breaking changes in their v5.0 API. We don't support that API yet.

@ronaldvdv
Copy link
Author

ronaldvdv commented Feb 19, 2020

Thanks, you're right! :-) And I would be interested in picking this up, too. Just from a design perspective I'm wondering - what is the main reason Splat was designed with mutable dependency containers in mind? What are the main things that would break or even become impossible (within Splat itself) without that? I can imagine if the problems within Splat are limited but many other projects depend on it, we could make a separate package Splat.Autofac5?

Edit: in my scenario, ReactiveUi is the main reason for using Splat. So I can imagine there's no simple solution without also considering changes to ReactiveUI and its initialization process...

@RLittlesII
Copy link
Member

RLittlesII commented Feb 19, 2020

My thought is it would be something we target for the next major release. If we need to provide early access to the package itself we can use GitHub Packages to release a version if you are in a pressing need to migrate to Autofac 5.x

Autofac provided examples of how it could be done. We just need to evaluate how to make those options work within the Splat Adapter.

As for Splat. It is a service locator, it is a dependent library for ReactiveUI. It was designed to be extremely lightweight and fast. There is already discussions around how we are going to overhaul the initialization, splat will still be at the root of that.

@ronaldvdv
Copy link
Author

ronaldvdv commented Feb 20, 2020

Indeed I looked at some of the open discussions in the ReactiveUI repository - it seems there are multiple :-D Not sure how to contribute best, but I guess the more difficult questions to be answered first are on ReactiveUI side. If we want ReactiveUI to cooperate nicely with DI frameworks that separate the service registration phase from the service resolving phase, the initialization "magic" in ReactiveUI needs a bit of redesigning: issue and rfc and follow these same two steps.

Perhaps a quick fix could be, that we have a mutable dependency resolver adapter for Autofac. It gets an original IContainer as a constructor argument. Whenever it is asked to make changes, it creates a new lifetime scope (see Autofac documentation) and then stores the updated container. Requests to the dependency resolver for resolving services are always forwarded to the most recent container.

This would not work perfectly if applications also create their own lifetime scopes - those scopes would never see the changes made using the mutable dependency resolver...

@skaman
Copy link

skaman commented Aug 14, 2020

Any news about this?

@skaman
Copy link

skaman commented Aug 16, 2020

At the moment I ended up to this workaround. It's far to be elegant but, until Splat will not correctly support it, this work for my needs.

In my case I'd like to use ReactiveUI with Blazor server and Autofac 5. The AutofacDependencyResolver will register every type to 2 differents ContainerBuilder. One is internal and is used to satisfy Splat (calling multiple times the BeginLifetimeScope to workaround the immutability), and the other one is the real ContainerBuilder of my application.

Here the custom AutofacDependencyResolver: https://gist.github.com/skaman/39506a11657dbaae69101eeeb3e4a5e0

Inside the startup, I used it in this way

public void ConfigureContainer(ContainerBuilder builder)
{
    var resolver = new AutofacDependencyResolver(builder);
    Locator.SetLocator(resolver);

    Locator.CurrentMutable.InitializeReactiveUI();

    builder.RegisterInstance(resolver);

    builder.RegisterType<MyType1>();
    builder.RegisterType<MyType2>();
    // and so on ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, QldbService qldbService)
{
    var lifetimeScope = app.ApplicationServices.GetAutofacRoot();
    var resolver = lifetimeScope.Resolve<AutofacDependencyResolver>();
    resolver.SetLifetimeScope(lifetimeScope);

    // continue with normal configure flow ...
}
Gist
AutofacDependencyResolver for AutoFac5 (temporary workaround until is correctly supported by Splat) - AutofacDependencyResolver.cs

@glennawatson
Copy link
Contributor

glennawatson commented Aug 16, 2020 via email

@HrlecMatej
Copy link
Contributor

I doubt that's likely to change, since the Autofac's Update method was removed so that containers can be generally immutable.

@glennawatson
Copy link
Contributor

We're unlikely to support autofac going into the future due to it.

@skaman
Copy link

skaman commented Sep 17, 2020

I doubt that's likely to change, since the Autofac's Update method was removed so that containers can be generally immutable.

I agree, immutability is a feature in autofac 5.x: https://autofaccn.readthedocs.io/en/latest/best-practices/#consider-a-container-as-immutable

@glennawatson
Copy link
Contributor

Closing this issue since we are just not going to support autofac 5

@skaman
Copy link

skaman commented Sep 17, 2020

May I ask, if you know, some suggestion about an alternative IoC container that is compatible with Splat and full featured like autofac? The main feature that i need in my project is the child scopes

@glennawatson
Copy link
Contributor

I'll research and get back to you on that one

@HrlecMatej
Copy link
Contributor

Autofac is the most popular .NET DI (at least by Github Stars), so I would probably not be the only one, who would prefer for a solution to be found.
skaman's workaround could perhaps be built upon, since child lifetime scopes are the only way Autofac supports any dynamic registrations.

@glennawatson
Copy link
Contributor

Hey there. locking this thread from further conversation.

@reactiveui reactiveui locked and limited conversation to collaborators Sep 17, 2020
@glennawatson
Copy link
Contributor

We will welcome pr for this issue but this is not a priority of the team at the moment.

@reactiveui reactiveui unlocked this conversation Sep 18, 2020
@glennawatson
Copy link
Contributor

Unlocked in case anyone wants to work out contact details to discuss offline for providing their own PR to splat.

@HrlecMatej
Copy link
Contributor

This is my attempt at a PR. Thank you to "skaman" for coming up with the workaround.

glennawatson pushed a commit that referenced this issue Sep 21, 2020
* feature: Update Splat.Autofac to work with Autofac 5.0 (#465)

Raises Autofac version to 5+, and deprecates or removes method that mutate the container (since that is supposed to be immutable from now on).
Register and HasRegister are to be used only by the ReactiveUI initialization procedure, which modifies the container by creating a child scope for each service registration.
Thanks to "skaman" for coming up with the workaround.

* UPDATE readme

* CHANGE Splat.Autofac tests, so they attempt to mutate the container anymore


CHANGE Splat.Autofac tests, so they attempt to mutate the container anymore

* FIX a few tests hopefully

* FIX 4 more tests for Unregistered by disabling them

* ADD check against adding registration to the dependency resolver after the container has been built

* CHANGE readme and container builder naming

* CHANGE Autofac version specifier
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants