{"id":11091,"date":"2024-09-01T17:16:31","date_gmt":"2024-09-01T17:16:31","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=11091"},"modified":"2024-09-01T17:16:31","modified_gmt":"2024-09-01T17:16:31","slug":"microsofts-dependency-injection","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/microsofts-dependency-injection\/","title":{"rendered":"Microsoft&#8217;s Dependency Injection"},"content":{"rendered":"<p>Dependency injection has been a fairly standard part of development for a while. You&#8217;ve probably used Unity, Autofac, Ninject and others in the past. <\/p>\n<p>Frameworks, such as ASP.NET core and MAUI use the Microsoft Dependency Injection package (Microsoft.Extensions.DependencyInjection) and we can use this with any other type of application. <\/p>\n<p>For example if we create ourselves a Console application, then add the package Microsoft.Extensions.DependencyInjection. Now can then use the following code<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar serviceCollection = new ServiceCollection();\r\n\r\n\/\/ add our services\r\n\r\nvar serviceProvider = serviceCollection.BuildServiceProvider();\r\n<\/pre>\n<p>and it&#8217;s as simple as that.<\/p>\n<p>The Microsoft.Extensions.DependencyInjection has most of the features we require for most dependency injection scenarios (Note: it does not support property injection for example). We can add services as&#8230;<\/p>\n<ul>\n<li><strong>Transient<\/strong> an instance created for every request, for example\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nserviceCollection.AddTransient&lt;IPipeline, Pipeline&gt;();\r\n\/\/ or\r\nserviceCollection.AddTransient&lt;Pipeline&gt;();\r\n<\/pre>\n<\/li>\n<li><strong>Singleton<\/strong> a single instance created and reused on every request, for example\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nserviceCollection.AddSingleton&lt;IPipeline, Pipeline&gt;();\r\n\/\/ or\r\nserviceCollection.AddSingleton&lt;Pipeline&gt;();\r\n<\/pre>\n<\/li>\n<li><strong>Scoped<\/strong> when we create a scope we get the same instance within the scope. In ASP.NET core a scope is created for each request\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nserviceCollection.AddScoped&lt;IPipeline, Pipeline&gt;();\r\n\/\/ or\r\nserviceCollection.AddScoped&lt;Pipeline&gt;();\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>For the services registered as &#8220;scoped&#8221;, if no scope is created then the code will work more or less like a singleton, i.e. the scope is the whole application, but if we want to mimic ASP.NET (for example) we would create a scope per request and we would do this by using the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing var scope = serviceProvider.CreateScope();\r\n\r\nvar pipeline1 = scope.ServiceProvider.GetRequiredService&lt;Pipeline&gt;();\r\nvar pipeline2 = scope.ServiceProvider.GetRequiredService&lt;Pipeline&gt;();\r\n<\/pre>\n<p>in the above code the same instance of the <em>Pipeline<\/em> is returned for each <em>GetRequiredService<\/em> call, but when the scope is disposed of or another scope created then a new instance for that scope will be returned.<\/p>\n<p>The service provider is used to create\/return instances of our services. We can use <em>GetRequiredService<\/em> which will throw and InvalidOperationException if the service is not registered or we might use <em>GetService<\/em> which will not throw an exception but will either return the instance or null.<\/p>\n<p><strong>Multiple services of the same type<\/strong><\/p>\n<p>If we register multiple implementations of our services like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nserviceCollection.AddTransient&lt;IPipeline, Pipeline1&gt;();\r\nserviceCollection.AddTransient&lt;IPipeline, Pipeline2&gt;();\r\n<\/pre>\n<p>and we use the service provider and use <em>GetRequiredService&lt;IPipeline&gt;<\/em> we will get a <em>Pipeline2<\/em> &#8211; it will be the the last registered type. <\/p>\n<p>If we want to get all services registered for type IPipeline then we use <em>GetServices&lt;IPipeline&gt;<\/em> and we&#8217;ll get an IEnumerable of IPipelines, so if we have a service which take an IPipeline, we&#8217;d need to declare it as follows<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class Context(IEnumerable&lt;IPipeline&gt; pipeline)\r\n{\r\n}\r\n<\/pre>\n<p>Finally we have the keyed option, this is allows use to register multiple variations of an interface (for example) and give each a key\/name, for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nserviceCollection.AddKeyedTransient&lt;IPipeline, Pipeline1&gt;(&quot;one&quot;);\r\nserviceCollection.AddKeyedTransient&lt;IPipeline, Pipeline2&gt;(&quot;two&quot;);\r\n<\/pre>\n<p>Now these will not be returned when using <em>GetServices&lt;IPipeline&gt;<\/em> instead it&#8217;s expected that we get the service by the key, i.e. <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar pipeline = serviceProvider.GetKeyedService&lt;IPipeline&gt;(&quot;one&quot;);\r\n<\/pre>\n<p>When declaring the requirement in our dependent classes we would use the FromKeyedServicesAttribute like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class Context(&#x5B;FromKeyedServices(&quot;one&quot;)] IPipeline pipeline)\r\n{\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Dependency injection has been a fairly standard part of development for a while. You&#8217;ve probably used Unity, Autofac, Ninject and others in the past. Frameworks, such as ASP.NET core and MAUI use the Microsoft Dependency Injection package (Microsoft.Extensions.DependencyInjection) and we can use this with any other type of application. For example if we create ourselves [&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":[3],"tags":[],"class_list":["post-11091","post","type-post","status-publish","format-standard","hentry","category-c"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11091","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=11091"}],"version-history":[{"count":4,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11091\/revisions"}],"predecessor-version":[{"id":11095,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11091\/revisions\/11095"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=11091"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=11091"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=11091"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}