question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Spec] Microsoft.Extensions.Hosting and/or Microsoft.Extensions.DependencyInjection

See original GitHub issue

Bake the features of Microsoft.Extensions.Hosting into .NET MAUI

https://montemagno.com/add-asp-net-cores-dependency-injection-into-xamarin-apps-with-hostbuilder/

Utilize the Generic Host structure that’s setup with .netcore 3.0 to initialize .NET MAUI applications.

This will provide users with a very Microsoft experience and will bring a lot of our code in line with ASP.NET core

Deeply root IServiceProvider into .NET MAUI

Replace all instances of Activator.CreateInstance(Type) with IServiceProvider.Get()

For example if we change this out on ElementTemplate https://github.com/dotnet/maui/blob/1a380f3c1ddd9ba76d1146bb9f806a6ed150d486/Xamarin.Forms.Core/ElementTemplate.cs#L26

Then any DataTemplate specified via type will take advantage of being created via constructor injection.

Examples

Host.CreateDefaultBuilder()
	.ConfigureHostConfiguration(c =>
	{
		c.AddCommandLine(new string[] { $"ContentRoot={FileSystem.AppDataDirectory}" });
		c.AddJsonFile(fullConfig);
	})
	.ConfigureServices((c, x) =>
	{
		nativeConfigureServices(c, x);
		ConfigureServices(c, x);
	})
	.ConfigureLogging(l => l.AddConsole(o =>
	{
		o.DisableColors = true;
	}))
	.Build();        

static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
	if (ctx.HostingEnvironment.IsDevelopment())
	{
		var world = ctx.Configuration["Hello"];
	}

	services.AddHttpClient();
	services.AddTransient<IMainViewModel, MainViewModel>();
	services.AddTransient<MainPage>();
	services.AddSingleton<App>();
}

Shell Examples

Shell is already string based and just uses types to create everything so we can easily hook into DataTemplates and provide ServiceCollection extensions

static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
     services.RegisterRoute(typeof(MainPage));
     services.RegisterRoute(typeof(SecondPage));
}

If all the DataTemplates are wired up through the IServiceProvider users could specify Interfaces on DataTemplates

<ShellContent ContentTemplate="{DataTemplate view:MainPage}"/ShellContent>
<ShellContent ContentTemplate="{DataTemplate view:ISecondPage}"></ShellContent>

Baked in constructor injection

public class App
{
        public App()
        {
            InitializeComponent();
            MainPage = ServiceProvider.GetService<MainPage>();
        }
}
public partial class MainPage : ContentPage
{
   public MainPage(IMainViewModel viewModel)
   {
            InitializeComponent();
            BindingContext = viewModel;
   }
}

public class MainViewModel
{
        public MainViewModel(ILogger<MainViewModel> logger, IHttpClientFactory httpClientFactory)
        {
            var httpClient = httpClientFactory.CreateClient();
            logger.LogCritical("Always be logging!");
            Hello = "Hello from IoC";
        }
}

This will allow Shell to also have baked in Constructor Injection

Routing.RegisterRoute("MainPage", MainPage)

GotoAsync("MainPage") // this will use the ServiceProvider to create the type

All the ContentTemplates specified as part of Shell will be created via the IServiceProvider

    <ShellContent
        x:Name="login"
        ContentTemplate="{DataTemplate MainPage}"
        Route="login" />

Implementation Details to consider

Use Microsoft.Build to facilitate the startup pipeline

Pull in the host features to articulate a specific startup location where things are registered https://montemagno.com/add-asp-net-cores-dependency-injection-into-xamarin-apps-with-hostbuilder/

This has the benefit of letting us tie into implementations of IoC containers that already work against asp.net core

Pros: This gives .NET developers a consistent experience. Cons: Performance? Is this overkill for mobile?

DI Container options

Deprecate DependencyService in favor of Microsoft.Extensions.DependencyInjection

Xamarin.Forms currently has a very simple home grown dependency service that doesn’t come with a lot of features. Growing the features of this service in the face of already available options doesn’t make much sense. In order to align ourselves more appropriately with other Microsoft Platforms we can switch over to the container inside Microsoft.Extensions.DependencyInjection.

Automatic registration of the DependencyService will be tied to the new registrar. If the user has opted in for the registrar to do assembly scanning than this will trigger the DependencyService to scan for assembly level attributes

One of the caveats of using this container is that types can’t be registered on the fly once the app has started. You can only register types as part of the startup process and then once the IServicePRovider is constructed that’s it. Registration is closed for business

Pros: It’s a full featured container Cons: Performance?

Convert our DependencyService to use IServiceCollection as an internal container and have it implement IServiceProvider

This would allow us to use a very slimmed down no featured container if people just want the best performance. We could probably use this as a default and then people could opt in for the more featured one if they want.

public class DependencyService : IServiceProvider
{
}

public static ServiceCollectionExtensions
{
     public static DependencyService Create(this IServiceCollection);
}

Considerations

Is this overall useful for a new users app experience? Do we really want to add the overhead of understanding a the build host startup loop for new users? It would probably be useful to just have a default setup for all of this that just uses Init and then new users can just easily do what they need to without having to setup settings files/configureservices/etc…

Performance

In my tests limited tests it takes about 25 ms for the Microsoft Hosting bits to startup. We’ll probably want to dive deeper into those 25 ms to see if we can get around it or if that cost is already part of a different startup cost we will already incur

Backward Compatibility

  • The current DependencyService scans for assembly level attributes which we will most likely shift to being opt in for .NET MAUI. The default will require you to register things via the Service Collection explicitly

Difficulty : Medium/Large

Existing work: https://github.com/xamarin/Xamarin.Forms/pull/8220

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:116
  • Comments:33 (15 by maintainers)

github_iconTop GitHub Comments

16reactions
SkyeHoeflingcommented, May 19, 2020

Something to consider when implementing this is using the Microsoft.Extensions.DependencyInjection.Abstractions project as the main dependency across the implementation in Maui. By reducing the footprint of Microsoft.Extensions.DependencyInjection to only be used on creating the container it will enable 3rd party libraries and frameworks to be agnostic of the container.

This enables a developer or framework the option to use a different container than the one provided by Maui. By using the abstractions project the work required by the developer or framework is just implementing the interfaces in the abstractions project. Where all of the Maui code will just use the interfaces. This will provide a massive extension point for everyone as we re-work how Dependency Injection works in the platform.

6reactions
aritchiecommented, May 19, 2020

think we should create a Startup.cs that sits right next to the App.cs or App.xaml.cs that handles all the startup code.

New users won’t want to figure out all of this bootstrapping stuff. In my opinion, this is the last thing you want especially since MAUI will alleviate all of the boilerplate around AppDelegate, MainActivity, etc. 1 startup/app.xaml to rule them all.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Tutorial: Use dependency injection in .NET
This tutorial shows how to use dependency injection (DI) in .NET. With Microsoft Extensions, DI is managed by adding services and ...
Read more >
.NET Standard 2.0 - Which Microsoft.Extensions. ...
This got me thinking that the version of the 'Microsoft.Extensions.DependencyInjection.Abstractions' package installed should match the .NET ...
Read more >
Dependency Injection - Microsoft.Extensions.Hosting vs ...
The Hosting and DependencyInjection components handle different concerns at different stages of the application's lifecycle. Stage 1: Hosts ...
Read more >
Add support for IHostedService · Issue #5
https://github.com/aspnet/Hosting/blob/master/src/Microsoft.Extensions.Hosting.Abstractions/ServiceCollectionHostedServiceExtensions.cs.
Read more >
Microsoft.Extensions.DependencyInjection 7.0.0
Version Downloads Last updated 8.0.0‑preview.7.23375.6 25,569 12 days ago 8.0.0‑preview.6.23329.7 76,445 a month ago 8.0.0‑preview.5.23280.8 89,539 2 months ago
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found