{"id":9421,"date":"2022-08-14T09:16:37","date_gmt":"2022-08-14T09:16:37","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=9421"},"modified":"2022-08-14T09:16:37","modified_gmt":"2022-08-14T09:16:37","slug":"dependency-injection-using-shell-in-maui","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/dependency-injection-using-shell-in-maui\/","title":{"rendered":"Dependency injection using Shell in MAUI"},"content":{"rendered":"<p>The MauiAppBuilder (as seen in the MauiProgram class) i.e.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar builder = MauiApp.CreateBuilder();\r\n<\/pre>\n<p>exposes the property <em>Services<\/em> which is a collection of ServiceDescriptor objects. This is where we register our &#8220;services&#8221;. We can use AddSingleton or AddTransient or AddScoped.<\/p>\n<p>So for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nbuilder.Services.AddSingleton&lt;MainPage&gt;();\r\nbuilder.Services.AddSingleton&lt;MainPageViewModel&gt;();\r\n<\/pre>\n<ul>\n<li><strong>AddSingleton<\/strong><br \/>\nAs the name suggests, a single instance of a type is created across the lifetime of the application.\n<\/li>\n<li>\n<strong>AddTransient<\/strong><br \/>\nA new instance of a type is created for each request, the equivalent of creating a new instance for every type that has a dependency, hence each gets a unique instance.\n<\/li>\n<li>\n<strong>AddScoped<\/strong><br \/>\nA new instance of a type is created for a request and all dependencies within that request gets the same instance. For different requests a new instance is created, hence unique across requests.\n<\/li>\n<\/ul>\n<p>Whilst the IoC container with MAUI Shell, isn&#8217;t as comprehensive in features as some containers, such as Autofac, it&#8217;s good enough for many. It does include constructor dependency injection so we will probably fulfil most use cases.<\/p>\n<p>Okay, let&#8217;s assume with have a MainPage and on that we have a button which displays an AboutPage. As per the code above suggests. We can create a view model for each page, so we have a MainPageViewModel and AboutPageViewModel, then within the actual .xaml.cs of those pages, in the constructor we have code such as <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic MainPage(MainPageViewModel vm)\r\n{\r\n   InitializeComponent();\r\n   BindingContext = vm;\r\n}\r\n\r\n\r\npublic AboutPage(AboutPageViewModel vm)\r\n{\r\n   InitializeComponent();\r\n   BindingContext = vm;\r\n}\r\n<\/pre>\n<p>Now all we need to do is register the pages and view models within the MauiProgram with the builder, so we have<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nbuilder.Services.AddSingleton&lt;MainPage&gt;();\r\nbuilder.Services.AddSingleton&lt;MainPageViewModel&gt;();\r\nbuilder.Services.AddTransient&lt;AboutPage&gt;();\r\nbuilder.Services.AddTransient&lt;AboutPageViewModel&gt;();\r\n<\/pre>\n<p>When Maui starts up and loads MainPage.xaml it will inject the MainPageViewModel and also when we navigate to our AboutPage using something like the code below, again the view model is injected<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;RelayCommand]\r\nprivate async Task About() =&gt; await AppShell.Current.GoToAsync(nameof(AboutPage));\r\n<\/pre>\n<p><em>Note: The example uses the MVVM Community Toolkit, hence the RelayCommandAttribute.<\/em><\/p>\n<p>We may need to resolve dependencies ourselves (in other words we&#8217;re unable to use the magic of something like constructor injection). Rather strangely I would have expected MAUI to already have code within for this, but it seems that current the solution is to create (or use an existing) ServiceProvider class. For example, the one shown below is taken from <a href=\"https:\/\/github.com\/davidortinau\/WeatherTwentyOne\/blob\/main\/src\/WeatherTwentyOne\/Services\/ServiceExtensions.cs\" rel=\"noopener\" target=\"_blank\">David Ortinau&#8217;s sample<\/a>. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\npublic static class ServiceProvider\r\n{\r\n   public static TService GetService&lt;TService&gt;()\r\n      =&gt; Current.GetService&lt;TService&gt;();\r\n\r\n   public static IServiceProvider Current\r\n      =&gt;\r\n#if WINDOWS10_0_17763_0_OR_GREATER\r\n\tMauiWinUIApplication.Current.Services;\r\n#elif ANDROID\r\n        MauiApplication.Current.Services;\r\n#elif IOS || MACCATALYST\r\n\tMauiUIApplicationDelegate.Current.Services;\r\n#else\r\n\tnull;\r\n#endif\r\n}\r\n<\/pre>\n<p>Now now we can use the static class ServiceProvider to get the Services, for example let&#8217;s remove the dependency injection in the AboutPage constructor and instead use the ServiceProvider like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nBindingContext = ServiceProvider.GetService&lt;AboutPageViewModel&gt;();\r\n<\/pre>\n<p>Ofcourse this is not so easily testable, but the option is there if required.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The MauiAppBuilder (as seen in the MauiProgram class) i.e. var builder = MauiApp.CreateBuilder(); exposes the property Services which is a collection of ServiceDescriptor objects. This is where we register our &#8220;services&#8221;. We can use AddSingleton or AddTransient or AddScoped. So for example builder.Services.AddSingleton&lt;MainPage&gt;(); builder.Services.AddSingleton&lt;MainPageViewModel&gt;(); AddSingleton As the name suggests, a single instance of a type [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[219,330],"tags":[],"class_list":["post-9421","post","type-post","status-publish","format-standard","hentry","category-ioc-2","category-maui"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/9421","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=9421"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/9421\/revisions"}],"predecessor-version":[{"id":9426,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/9421\/revisions\/9426"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=9421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=9421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=9421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}