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

Prism.Forms dependency injection IServiceCollection problem #1352

Closed
tibitoth opened this issue Jan 28, 2018 · 4 comments
Closed

Prism.Forms dependency injection IServiceCollection problem #1352

tibitoth opened this issue Jan 28, 2018 · 4 comments

Comments

@tibitoth
Copy link

tibitoth commented Jan 28, 2018

Description

As you might already know Microsoft provides a DI abstraction and implementation in the Microsoft.Extensions.DependencyInjection package. Many other libraries have been already integrated with the IServiceCollection interface eg.: Entity Framework Core, Logging, (HttpClientFactory) etc. Currently I'm experimenting with the new Prism DI system to integrate with Microsoft's IServiceCollection. It's not so easy but I've figured out a workaround with some issues (tried with Prism.Forms.Autofac):

In the following code you can see, that I'm overriding the CreateContainerExtension to call ContainerBuilder.Populate(IServiceCollection services); method for the Autofac <--> MS.Ext.DI integration with logging and Entity Framework services.

public partial class App
{
    public App()
    {
        InitializeComponent();
    }

    protected override IContainerExtension CreateContainerExtension()
    {
        var containerExtension = (IAutofacContainerExtension)base.CreateContainerExtension();

        var services = new ServiceCollection();

        services.AddLogging(config => config.AddDebug());

        services.AddDbContext<AppDbContext>(
            config => config.UseSqlite("Data Source = " + Path.Combine(FileSystem.Current.LocalStorage.Path, "test.db")));

        containerExtension.Builder.Populate(services);

        return containerExtension;
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation<MainPage>("Main");
    }

    protected override async void OnInitialized()
    {
        await NavigationService.NavigateAsync("Main");
    }
}

In my MainPageViewModel I've just try to resolve the AppDbContext and an ILogger.

public class MainPageViewModel : BindableBase
{
    public MainPageViewModel(AppDbContext dbContext, ILogger<MainPageViewModel> logger)
    {
        dbContext.Database.EnsureCreated();
        dbContext.Persons.Add(new Person() { Name = "Test" });
        dbContext.SaveChanges();
        var p = dbContext.Persons.First();

        logger.LogInformation("MPVM ctor called");
    }
}

So my first issue is maybe it was bad choice to not support Microsoft.Extensions.DependencyInjection but I know you don't want to change on this.

Secondly the code above is not working currently because of this line of your codebase: Builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource()); In my case this messes up the service registrations regarding to Entity Framework's services. I think you are using this operation to resolve ViewModel types. Are there any other aspects of this? If not than we should register ViewModels in a different way. It will be more and more commonly to use MS.Ext.DI.

If I remove the Builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource()); line and register ViewModel types by hand it works flawlessly.

I've tested only in UWP because EFCore has some open issues with Android dotnet/efcore#8922

I will update my post with details of other DI providers.

Thanks.

Basic Information

  • Version with issue: Prism.Forms.Autofac 7.0
  • Last known good version: None
  • Xamarin.Forms version: 2.5.0.122203
  • IDE: VS2017
@brianlagunas
Copy link
Member

You can create your own IContainerExtension and use that instead. Also, using the MS DI abstractions is not an option. It is not compatible with the requirements of Prism. Our DI abstraction cannot be immutable, and requires the registration and resolution by name. These are non-negotiables.

@tibitoth
Copy link
Author

Sure thanks, one more question please: Are you using this particular line Builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource()); only for ViewModel registrations or is there any other reason?

@brianlagunas
Copy link
Member

Its mainly for auto ViewModel registrations. Otherwise an exception would be thrown unless you manually registered the ViewModels separately.

@lock
Copy link

lock bot commented Jan 29, 2020

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

@lock lock bot locked as resolved and limited conversation to collaborators Jan 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants