DEV Community: Dev Leader The latest articles on DEV Community by Dev Leader (@devleader). https://dev.to/devleader https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1013199%2F0d622a58-9438-432c-8a28-7cf52d80f6e3.png DEV Community: Dev Leader https://dev.to/devleader en How To Use IServiceCollection In Console Applications – What You Need To Know Dev Leader Mon, 20 May 2024 14:00:00 +0000 https://dev.to/devleader/how-to-use-iservicecollection-in-console-applications-what-you-need-to-know-17e https://dev.to/devleader/how-to-use-iservicecollection-in-console-applications-what-you-need-to-know-17e <p>When it comes to dependency injection and using the built-in IServiceCollection, the framing feels such that we’re restricted to <a href="proxy.php?url=http://ASP.NET" rel="noopener noreferrer">ASP.NET</a> Core. So if we wanted to use <code>IServiceCollection</code> in console applications instead, what options do we have?</p> <p>It turns out that we absolutely can! In this article, I’ll touch on one of the Microsoft Learn articles as well as explain an alternative approach… That you can run right in your browser with dotnetfiddle!</p> <h2> <strong>Microsoft Learn Article on IServiceCollection in Console Applications</strong> </h2> <p>Microsoft Learn is a tremendous source of valuable information. I feel like in recent years it continues to surprise me how much valuable information we can find there since I’m used to just relying on MSDN for doc comments and maybe the odd helpful example.</p> <p>However, in this case, I was a little taken back because the article seemed to be a little bit more cumbersome than I was expecting. If our goal is just to be able to use the <code>IServiceCollection</code> interface so that we can work with our familiar dependency injection API, I would hope that we can stick to the basics.</p> <p>However, it looks like <a href="proxy.php?url=https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-usage#register-services-for-di" rel="noopener noreferrer">the example in the tutorial</a> goes a little bit beyond that and demonstrates the usage of an <code>HostApplicationBuilder</code>.</p> <h3> <strong>HostApplicationBuilder For Dependency Injection</strong> </h3> <p>Let’s look at the example code, which is <a href="proxy.php?url=https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-usage" rel="noopener noreferrer">taken directly from the Microsoft Learn article</a>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Microsoft.Extensions.DependencyInjection</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Microsoft.Extensions.Hosting</span><span class="p">;</span> <span class="k">using</span> <span class="nn">ConsoleDI.Example</span><span class="p">;</span> <span class="n">HostApplicationBuilder</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">Host</span><span class="p">.</span><span class="nf">CreateApplicationBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">IExampleTransientService</span><span class="p">,</span> <span class="n">ExampleTransientService</span><span class="p">&gt;();</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddScoped</span><span class="p">&lt;</span><span class="n">IExampleScopedService</span><span class="p">,</span> <span class="n">ExampleScopedService</span><span class="p">&gt;();</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IExampleSingletonService</span><span class="p">,</span> <span class="n">ExampleSingletonService</span><span class="p">&gt;();</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">ServiceLifetimeReporter</span><span class="p">&gt;();</span> <span class="k">using</span> <span class="nn">IHost</span> <span class="n">host</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="nf">ExemplifyServiceLifetime</span><span class="p">(</span><span class="n">host</span><span class="p">.</span><span class="n">Services</span><span class="p">,</span> <span class="s">"Lifetime 1"</span><span class="p">);</span> <span class="nf">ExemplifyServiceLifetime</span><span class="p">(</span><span class="n">host</span><span class="p">.</span><span class="n">Services</span><span class="p">,</span> <span class="s">"Lifetime 2"</span><span class="p">);</span> <span class="k">await</span> <span class="n">host</span><span class="p">.</span><span class="nf">RunAsync</span><span class="p">();</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ExemplifyServiceLifetime</span><span class="p">(</span><span class="n">IServiceProvider</span> <span class="n">hostProvider</span><span class="p">,</span> <span class="kt">string</span> <span class="n">lifetime</span><span class="p">)</span> <span class="p">{</span> <span class="k">using</span> <span class="nn">IServiceScope</span> <span class="n">serviceScope</span> <span class="p">=</span> <span class="n">hostProvider</span><span class="p">.</span><span class="nf">CreateScope</span><span class="p">();</span> <span class="n">IServiceProvider</span> <span class="n">provider</span> <span class="p">=</span> <span class="n">serviceScope</span><span class="p">.</span><span class="n">ServiceProvider</span><span class="p">;</span> <span class="n">ServiceLifetimeReporter</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">provider</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">ServiceLifetimeReporter</span><span class="p">&gt;();</span> <span class="n">logger</span><span class="p">.</span><span class="nf">ReportServiceLifetimeDetails</span><span class="p">(</span> <span class="s">$"</span><span class="p">{</span><span class="n">lifetime</span><span class="p">}</span><span class="s">: Call 1 to provider.GetRequiredService&lt;ServiceLifetimeReporter&gt;()"</span><span class="p">);</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"..."</span><span class="p">);</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">provider</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">ServiceLifetimeReporter</span><span class="p">&gt;();</span> <span class="n">logger</span><span class="p">.</span><span class="nf">ReportServiceLifetimeDetails</span><span class="p">(</span> <span class="s">$"</span><span class="p">{</span><span class="n">lifetime</span><span class="p">}</span><span class="s">: Call 2 to provider.GetRequiredService&lt;ServiceLifetimeReporter&gt;()"</span><span class="p">);</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">();</span> <span class="p">}</span> </code></pre> </div> <p>There’s a lot going on here, of course, because they want to use a single example to demonstrate a few different things. However, my biggest challenges with this is that we can see the <code>IServiceCollection</code> being used via the <code>builder.Services</code> property call… but why do we need to go make an entire hosted application here?</p> <p>Now, I’m not claiming that you shouldn’t use a hosted application or anything like that — but I am saying that this feels a little bit heavy-handed. If I just want to use <code>IServiceCollection</code> then why am I required to build a hosted application?</p> <h2> <strong>Using IServiceCollection in Console Applications Directly</strong> </h2> <p>It turns out that it’s not complex rocket surgery to get this to work without the hosted application pieces from the Microsoft Learn example. That’s important for me because I want to provide people alternatives when I create content about Autofac and they just want to use IServiceCollection like they are familiar with.</p> <p>Let’s look at this <a href="proxy.php?url=https://dotnetfiddle.net/J0U1mm" rel="noopener noreferrer">example code which you can see directly on dotnetfiddle</a>:</p> <p><iframe src="proxy.php?url=https://dotnetfiddle.net/Widget/J0U1mm" width="100%" height="600"> </iframe> </p> <p>Simply, we can create a new service collection by creating a new <code>ServiceCollection</code> instance:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">var</span> <span class="n">services</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceCollection</span><span class="p">();</span> </code></pre> </div> <p>Interestingly there was no dependency on having a hosted application or any other type of builder to do this. We can leverage it directly. It’s also important to note in the dotnetfiddle example that I shared that there are no Nugets imported. So we are able to create this instance without additional packages added.</p> <p>From there, we can start to register our dependencies directly onto the <code>IServiceCollection</code> (keeping in mind I am only illustrating one type of dependency here):<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">MyService</span><span class="p">&gt;();</span> <span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">MyDependency</span><span class="p">&gt;();</span> </code></pre> </div> <p>However, this is just the service collection and we still need to create the instance of a service provider that we can resolve dependencies from:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">var</span> <span class="n">serviceProvider</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">BuildServiceProvider</span><span class="p">();</span> </code></pre> </div> <p>With the service provider available, we can go ahead and resolve dependencies directly from it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">var</span> <span class="n">myService</span> <span class="p">=</span> <span class="n">serviceProvider</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">MyService</span><span class="p">&gt;();</span> </code></pre> </div> <h2> <strong>Wrapping Up IServiceCollection in Console Applications</strong> </h2> <p>To wrap up this article, we don’t need to go with a hosted application if we want to leverage an <code>IServiceCollection</code> in console applications for dependency injection. While the Microsoft Learn article is awesome with plenty of solid examples, I felt like it overcomplicated what could otherwise be a bit more straightforward.</p> <p>So if you’re looking to go leverage an <code>IServiceCollection</code> in your console projects instead of Autofac, go nuts! Even though I like using Autofac for all of my dependency injection, I think it’s important to understand the options that you have!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> coding programming csharp dotnet Autofac ComponentRegistryBuilder in ASP.NET Core – How To Register Dependencies Dev Leader Thu, 09 May 2024 14:00:00 +0000 https://dev.to/devleader/autofac-componentregistrybuilder-in-aspnet-core-how-to-register-dependencies-ejp https://dev.to/devleader/autofac-componentregistrybuilder-in-aspnet-core-how-to-register-dependencies-ejp <p>In this article, we’ll be exploring how to use Autofac ComponentRegistryBuilder in ASP.NET Core. Prior articles in this series have highlighted some challenges for getting set up to do C# plugin architectures — at least for my own standards. I’ll be walking us through how this approach can help overcome some of the challenges that have previously been highlighted.</p> <p>This will be part of a series where I explore dependency resolution with Autofac inside of ASP.NET Core. I'll be sure to include the series below as the issues are published:</p> <ul> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/04/30/autofacserviceproviderfactory-in-asp-net-core-problems-with-dependency-injection-part-1/" rel="noopener noreferrer">Part 1: AutofacServiceProviderFactory in ASP.NET Core - Problems With Dependency Injection</a></p></li> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/05/02/autofac-containerbuilder-in-asp-net-core-what-you-need-to-know-part-2" rel="noopener noreferrer">Part 2: Autofac ContainerBuilder In ASP.NET Core – What You Need To Know</a></p></li> <li><p><a>Part 3: Autofac ComponentRegistryBuilder in ASP.NET Core - How To Register Dependencies</a></p></li> </ul> <p>At the end of this series, you'll be able to more confidently explore plugin architectures inside of ASP.NET Core and Blazor -- which will be even more content for you to explore. Keep your eyes peeled on <a href="proxy.php?url=https://dometrain.com/author/nick-cosentino?affcode=1115529_nl-teyzg" rel="noopener noreferrer">my Dometrain courses for a more guided approach to these topics later in 2023</a>.</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Where Did We Leave Off With Autofac in ASP.NET Core?</strong> </h2> <p>The previous two articles looked at the following scenarios:</p> <ul> <li><p>Setting up using the <code>AutofacServiceProviderFactory</code> as the standard recommended approach</p></li> <li><p>Skipping <code>AutofacServiceProviderFactory</code> and using Autofac <code>ContainerBuilder</code> directly</p></li> </ul> <p>In both cases, we were able to get a web application up and running using Autofac for dependency injection. However, both of these had limitations around:</p> <ul> <li><p>Accessing the <code>WebApplication</code> instance on the container</p></li> <li><p>Weird nuances with minimal API support</p></li> </ul> <p>While both options are absolutely viable — and may be great for you given your constraints — I wanted to push a bit further to see if the wrinkles could be ironed out. I want to strive towards having configuration done in <a href="proxy.php?url=https://www.devleader.ca/2023/10/02/how-to-organize-autofac-modules-5-tips-for-organizing-code/" rel="noopener noreferrer">separate Autofac modules</a> and pushing towards a C# plugin architecture for the majority of my application development.</p> <h2> <strong>Exploring A Sample ASP.NET Core Application</strong> </h2> <p>This one is going to be different than the previous articles — we’ve achieved plugin status. I want to show you how the code from the previous examples can now be broken out into more dedicated pieces. Most of what we’ve gone over before is the same concept, but I’ve reduced the weather route to something more contrived just to eliminate the waste.</p> <p>Make sure to follow along with <a href="proxy.php?url=https://youtu.be/JYD0VKKXle8" rel="noopener noreferrer">this video on Autofac</a> for additional explanations as we go through:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/JYD0VKKXle8"> </iframe> </p> <h3> <strong>The Entry Point Configuration</strong> </h3> <p>Here’s how simple our Program.cs file is now:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">await</span> <span class="k">new</span> <span class="nf">FullResolveWebApi</span><span class="p">().</span><span class="nf">RunAsync</span><span class="p">(</span><span class="n">CancellationToken</span><span class="p">.</span><span class="n">None</span><span class="p">);</span> </code></pre> </div> <p>That’s right — one line of code. But okay, you’re probably curious where all the setup actually takes place. Let’s go a bit deeper:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">FullResolveWebApi</span> <span class="p">{</span> <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">containerBuilder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MyContainerBuilder</span><span class="p">();</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">scope</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="nf">BeginLifetimeScope</span><span class="p">();</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">scope</span> <span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">ConfiguredWebApplication</span><span class="p">&gt;()</span> <span class="p">.</span><span class="n">WebApplication</span><span class="p">;</span> <span class="k">await</span> <span class="n">app</span><span class="p">.</span><span class="nf">RunAsync</span><span class="p">(</span><span class="n">cancellationToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>This looks familiar to what we saw in the previous example! We’re able to get the goodness of that really lean startup configuration But wait! What’s that custom <code>MyContainerBuilder</code> class?!<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">using</span> <span class="nn">System.Reflection</span><span class="p">;</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">MyContainerBuilder</span> <span class="p">{</span> <span class="k">public</span> <span class="n">IContainer</span> <span class="nf">Build</span><span class="p">()</span> <span class="p">{</span> <span class="n">ContainerBuilder</span> <span class="n">containerBuilder</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> <span class="c1">// TODO: do some assembly scanning if needed</span> <span class="kt">var</span> <span class="n">assembly</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="nf">GetExecutingAssembly</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="nf">RegisterAssemblyModules</span><span class="p">(</span><span class="n">assembly</span><span class="p">);</span> <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="k">return</span> <span class="n">container</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>This is missing from the code above if we compare it to the previous article, but it can also be extended to do assembly scanning if that’s a requirement. So far, so good. We have one more piece though, and that’s <code>ConfiguredWebApplication</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">ConfiguredWebApplication</span><span class="p">(</span> <span class="n">WebApplication</span> <span class="n">_webApplication</span><span class="p">,</span> <span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">PreApplicationConfiguredMarker</span><span class="p">&gt;</span> <span class="n">_markers</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="n">WebApplication</span> <span class="n">WebApplication</span> <span class="p">=&gt;</span> <span class="n">_webApplication</span><span class="p">;</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">record</span> <span class="nc">PreApplicationBuildMarker</span><span class="p">();</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">record</span> <span class="nc">PreApplicationConfiguredMarker</span><span class="p">();</span> </code></pre> </div> <p>This marker record might seem a bit confusing but we’ll tie this all together in a dedicated section.</p> <h3> <strong>WebApplicationBuilder Autofac Module</strong> </h3> <p>Now that we’ve seen how our initial ASP NET Core application bootstrap code is looking, it’s time to look at some of the core dependency registration that’s going to be a union of what we saw in the previous articles AND some new behavior:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Autofac.Extensions.DependencyInjection</span><span class="p">;</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">WebApplicationBuilderModule</span> <span class="p">:</span> <span class="k">global</span><span class="p">::</span><span class="n">Autofac</span><span class="p">.</span><span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">Environment</span><span class="p">.</span><span class="nf">GetCommandLineArgs</span><span class="p">());</span> <span class="k">return</span> <span class="n">builder</span><span class="p">;</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplicationBuilder</span><span class="p">&gt;().</span><span class="n">Configuration</span><span class="p">;</span> <span class="k">return</span> <span class="n">config</span><span class="p">;</span> <span class="p">})</span> <span class="p">.</span><span class="n">As</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">WebApplication</span><span class="p">?</span> <span class="n">cachedWebApplication</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">cachedWebApplication</span> <span class="k">is</span> <span class="k">not</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">cachedWebApplication</span><span class="p">;</span> <span class="p">}</span> <span class="kt">var</span> <span class="n">webApplicationBuilder</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplicationBuilder</span><span class="p">&gt;();</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">PreApplicationBuildMarker</span><span class="p">&gt;&gt;();</span> <span class="n">webApplicationBuilder</span><span class="p">.</span><span class="n">Host</span><span class="p">.</span><span class="nf">UseServiceProviderFactory</span><span class="p">(</span><span class="k">new</span> <span class="nf">AutofacServiceProviderFactory</span><span class="p">(</span><span class="n">containerBuilder</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">registration</span> <span class="k">in</span> <span class="n">ctx</span><span class="p">.</span><span class="n">ComponentRegistry</span><span class="p">.</span><span class="n">Registrations</span><span class="p">)</span> <span class="p">{</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">ComponentRegistryBuilder</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">registration</span><span class="p">);</span> <span class="p">}</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">RegisterInstance</span><span class="p">(</span><span class="n">webApplicationBuilder</span><span class="p">)</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}));</span> <span class="n">cachedWebApplication</span> <span class="p">=</span> <span class="n">webApplicationBuilder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="k">return</span> <span class="n">cachedWebApplication</span><span class="p">;</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="n">app</span><span class="p">.</span><span class="nf">UseHttpsRedirection</span><span class="p">();</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">PreApplicationConfiguredMarker</span><span class="p">();</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span> <span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">ConfiguredWebApplication</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>You’ll notice that the code snippet above shows that we’re now mixing in the <code>AutofacServiceProviderFactory</code> alongside our standalone Autofac <code>ContainerBuilder</code> approach. What we’re able to do is leverage this code to re-register some of the dependency registrations on the second Autofac <code>ContainerBuilder</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">registration</span> <span class="k">in</span> <span class="n">ctx</span><span class="p">.</span><span class="n">ComponentRegistry</span><span class="p">.</span><span class="n">Registrations</span><span class="p">)</span> <span class="p">{</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">ComponentRegistryBuilder</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">registration</span><span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>Now that we can duplicate our registrations, we get the registration of the <code>WebApplication</code> from the parent container onto the dedicated <code>WebApplication</code>‘s <code>ContainerBuilder</code>. But two things we should note:</p> <ul> <li><p>We need to cache the <code>WebApplication</code> instance. This is because later on when the <code>WebApplication</code> instance itself needs to resolve dependencies that depend on an instance of <code>WebApplication</code>, it will go re-run the registration <em>even though it’s a single instance</em>! This is because this is a duplicated registration across the container that has never technically been executed at the time of registration. We may need to pay special attention to this sort of thing as we go forward to avoid expensive re-resolution of types.</p></li> <li><p>We see another marker type: <code>PreApplicationConfiguredMarker</code>. What’s with these markers?!</p></li> </ul> <h3> <strong>Marker Classes for Controlling Dependency Ordering and Requirements</strong> </h3> <p>So far we’ve seen two instances of marker types. These marker types are a way that we can force certain registration code to execute before some other registration code executes. This is a more flexible way of saying “I don’t care which types specifically get registered or which registration code runs, but anyone that needs to be registered before some checkpoint, make sure you return one of these”. This allows us to force code to execute before a checkpoint.</p> <p>If we consider the code in the example above, we see that the <code>ConfiguredWebApplication</code> instance requires the full collection of <code>PreApplicationConfiguredMarker</code> instances. This means that we can’t even create an instance of <code>ConfiguredWebApplication</code> until all dependent code, as indicated by our marker type, has finished executing. This essentially forces Autofac to run certain code for us because it will attempt to run all code that provides one of these marker instances.</p> <p>The two markers we see in this example code are very naive/primitive — however, this concept can be expanded to provide more robust checkpoints in your dependency registration process.</p> <h2> <strong>CSharp Plugin Architecture in ASP.NET Core Unlocked!</strong> </h2> <p>The cat’s out of the bag! We can now successfully create an Autofac module for a plugin! This code shows us enabling C# plugin architecture in ASP.NET Core as we’re able to add a new discoverable module that adds its own API endpoints:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">namespace</span> <span class="nn">Plugins</span><span class="p">;</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">PluginModule</span> <span class="p">:</span> <span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// load whatever dependencies you want in your plugin</span> <span class="c1">// taking note that they will be able to have access</span> <span class="c1">// to services/dependencies in the main application</span> <span class="c1">// by default</span> <span class="n">builder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyA</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyB</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyC</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="c1">// minimal APIs can resolve dependencies from the</span> <span class="c1">// method signature itself</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span> <span class="s">"/hello"</span><span class="p">,</span> <span class="p">(</span> <span class="n">DependencyA</span> <span class="n">dependencyA</span> <span class="p">,</span> <span class="n">DependencyB</span> <span class="n">dependencyB</span> <span class="p">,</span> <span class="n">DependencyC</span> <span class="n">dependencyC</span> <span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">return</span> <span class="k">new</span> <span class="p">{</span> <span class="n">AAA</span> <span class="p">=</span> <span class="n">dependencyA</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="n">BBB</span> <span class="p">=</span> <span class="n">dependencyB</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="n">CCC</span> <span class="p">=</span> <span class="n">dependencyC</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="p">};</span> <span class="p">});</span> <span class="c1">// this is a marker to signal a dependency</span> <span class="c1">// before the application can be considered</span> <span class="c1">// configured</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">PreApplicationConfiguredMarker</span><span class="p">();</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyA</span><span class="p">(</span> <span class="n">WebApplicationBuilder</span> <span class="n">_webApplicationBuilder</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">ToString</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_webApplicationBuilder</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyB</span><span class="p">(</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;</span> <span class="n">_webApplication</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">ToString</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_webApplication</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyC</span><span class="p">(</span> <span class="n">IConfiguration</span> <span class="n">_configuration</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">ToString</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_configuration</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span> <span class="p">}</span> </code></pre> </div> <p>If you’d like a more full explanation as to what you’re seeing, I highly recommend you read the articles linked at the top of this one first just to get an idea of why we have some dependencies set up like this. The TL;DR is that this code demonstrates that we can access some dependencies that are of interest to us when building plugin architectures.</p> <h3> <strong>What Benefits For CSharp Plugin Architecture Have Been Unlocked?</strong> </h3> <p>The code examples in this article are essentially marrying approaches from two of the previous articles… so hopefully we have the best of both worlds! Let’s have a look:</p> <ul> <li><p>Can access <code>WebApplicationBuilder</code> instance from the <code>WebApplication</code>‘s dependency container.</p></li> <li><p>Can access <code>IConfiguration</code> instance from the <code>WebApplication</code>‘s dependency container.</p></li> <li><p>Can access <code>WebApplication</code> instance from the <code>WebApplication</code>‘s dependency container.</p></li> <li><p>Can resolve Autofac ContainerBuilder dependencies on the minimal APIs directly</p></li> <li><p>Can create separate Autofac modules (i.e. for plugin usage) that register minimal APIs directly onto the <code>WebApplication</code> instance</p></li> <li><p>Can get an extremely lightweight (one line!) entry point to our application. The core “skeleton” application code is fundamentally just setting up dependencies to be resolved.</p></li> </ul> <p>All of these are boxes that I wanted to check before continuing to build plugins. With this infrastructure in place, I feel much more confident!</p> <h3> <strong>What Gaps Are Left For CSharp Plugin Architecture?</strong> </h3> <p>Of course, we need to look at both pros AND cons when we analyze things. Let’s dive in:</p> <ul> <li><p>We have two dependency containers to worry about. In theory, the usage of Autofac ComponentRegistryBuilder in ASP.NET Core should allow us to clone registrations between the two, but more complexity can potentially arise from this as we continue.</p></li> <li><p>We saw an interesting need to cache the <code>WebApplication</code> instance to avoid dependency recreation — are there other scenarios like this we haven’t hit yet?</p></li> <li><p>One of the general plugin architecture concerns: Being able to configure EVERYTHING with plugins can make some things harder to find and structure. Do we really need these little marker types to help organize ourselves?</p></li> </ul> <h2> <strong>Wrapping Up Autofac ComponentRegistryBuilder in ASP.NET Core</strong> </h2> <p>Overall, I’m quite happy with how using Autofac ComponentRegistryBuilder in ASP.NET Core has allowed us to progress our dependency injection patterns. This approach which I’ve highlighted in the article has made it significantly easier for me to go structure plugins the way that I’d like to in a C# plugin architecture. Not without tradeoffs — but I feel this pattern fits my needs.</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> webdev dotnet csharp programming Autofac ContainerBuilder in ASP.NET Core – What You Need To Know Dev Leader Wed, 08 May 2024 14:00:00 +0000 https://dev.to/devleader/autofac-containerbuilder-in-aspnet-core-what-you-need-to-know-475e https://dev.to/devleader/autofac-containerbuilder-in-aspnet-core-what-you-need-to-know-475e <p>There are many ways to manage dependency injection inside our applications, and I think it’s important to understand the benefits and limitations of different approaches. Using an Autofac <code>ContainerBuilder</code> in ASP.NET Core as the primary way to structure your dependencies instead of using the suggested <code>AutofacServiceProviderFactory</code> is one such path we can explore!</p> <p>In this article, I highlight how to use Autofac’s ContainerBuilder in your ASP.NET Core application instead of the AutofacServiceProviderFactory. We’ll look at what you can and cannot do with this approach, versus the other approaches we have access to with dependency injection.</p> <p>This will be part of a series where I explore dependency resolution with Autofac inside of ASP.NET Core. I'll be sure to include the series below as the issues are published:</p> <ul> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/04/30/autofacserviceproviderfactory-in-asp-net-core-problems-with-dependency-injection-part-1/" rel="noopener noreferrer">Part 1: AutofacServiceProviderFactory in ASP.NET Core - Problems With Dependency Injection</a></p></li> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/05/02/autofac-containerbuilder-in-asp-net-core-what-you-need-to-know-part-2" rel="noopener noreferrer">Part 2: Autofac ContainerBuilder In ASP.NET Core – What You Need To Know</a></p></li> <li><p><a>Part 3: Autofac ComponentRegistryBuilder in ASP.NET Core - How To Register Dependencies</a></p></li> </ul> <p>At the end of this series, you'll be able to more confidently explore plugin architectures inside of ASP.NET Core and Blazor -- which will be even more content for you to explore. Keep your eyes peeled on <a href="proxy.php?url=https://dometrain.com/author/nick-cosentino?affcode=1115529_nl-teyzg" rel="noopener noreferrer">my Dometrain courses for a more guided approach to these topics later in 2023</a>.</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>The Problem With AutofacServiceProviderFactory</strong> </h2> <p>To be fair, the section title is <em>almost</em> click-bait. I do think that <code>AutofacServiceProviderFactory</code> being used as <a href="proxy.php?url=https://www.devleader.ca/2024/03/19/autofac-in-asp-net-core-how-to-avoid-this-debugging-nightmare/" rel="noopener noreferrer">the suggested way to set up Autofac in your ASP.NET Core applications</a> is great for most applications. The great majority of developers who want to use Autofac as their dependency injection framework of choice would not run into many issues at all this way.</p> <p>It does afford us the ability to:</p> <ul> <li><p>Access the <code>WebApplicationBuilder</code> (and anything available at this point in time)</p></li> <li><p>Access to the instance of <code>IConfiguration</code> (also available off the <code>WebApplicationBuilder</code> instance)</p></li> <li><p>Ability to pass dependencies onto minimal APIs</p></li> </ul> <p>But the big issue for me: We can’t access the <code>WebApplication</code> instance. When I build plugin architectures in C#, in particular building ASP.NET Core applications, I like to have access to the <code>WebApplication</code> instance in order to register routes. This allows me to register minimal APIs from my plugins with ease, which technically only need access to an implementation of <code>IEndpointRouteBuilder</code> to get the handy syntax.</p> <p>Can I register non-minimal APIs without this? Absolutely. Is there another way to provide similar syntax and not require a <code>WebApplication</code> instance? Very likely. But instead of trying to work around THAT problem, I wanted to see if I could just get access to the dependency I am interested in.</p> <p>It was time to change the plan on how to set up my dependency container!</p> <h2> <strong>Exploring A Sample ASP.NET Core Application</strong> </h2> <p>Let’s look at a sample application so that we have some common ground to explore. If you’ve <a href="proxy.php?url=https://www.devleader.ca/2024/04/30/autofacserviceproviderfactory-in-asp-net-core-problems-with-dependency-injection-part-1/" rel="noopener noreferrer">read the previous article</a>, this will look similar — a variation of the sample weather application:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span> <span class="c1">// personal opinion:</span> <span class="c1">// I absolutely love having the entry point of my</span> <span class="c1">// applications being essentially:</span> <span class="c1">// - make my dependencies</span> <span class="c1">// - give me the primary dependency</span> <span class="c1">// - use it</span> <span class="c1">// - ... nothing else :)</span> <span class="n">ContainerBuilder</span> <span class="n">containerBuilder</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterModule</span><span class="p">&lt;</span><span class="n">MyModule</span><span class="p">&gt;();</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">scope</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="nf">BeginLifetimeScope</span><span class="p">();</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">scope</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="n">app</span><span class="p">.</span><span class="nf">Run</span><span class="p">();</span> <span class="k">internal</span> <span class="k">record</span> <span class="nc">WeatherForecast</span><span class="p">(</span><span class="n">DateOnly</span> <span class="n">Date</span><span class="p">,</span> <span class="kt">int</span> <span class="n">TemperatureC</span><span class="p">,</span> <span class="kt">string</span><span class="p">?</span> <span class="n">Summary</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="kt">int</span> <span class="n">TemperatureF</span> <span class="p">=&gt;</span> <span class="m">32</span> <span class="p">+</span> <span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">TemperatureC</span> <span class="p">/</span> <span class="m">0.5556</span><span class="p">);</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">MyModule</span> <span class="p">:</span> <span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">containerBuilder</span><span class="p">)</span> <span class="p">{</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyA</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyB</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyC</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">Environment</span><span class="p">.</span><span class="nf">GetCommandLineArgs</span><span class="p">());</span> <span class="k">return</span> <span class="n">builder</span><span class="p">;</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplicationBuilder</span><span class="p">&gt;().</span><span class="n">Configuration</span><span class="p">)</span> <span class="p">.</span><span class="n">As</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplicationBuilder</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="n">app</span><span class="p">.</span><span class="nf">UseHttpsRedirection</span><span class="p">();</span> <span class="c1">// FIXME: the problem is that the Autofac ContainerBuilder</span> <span class="c1">// was used to put all of these pieces together,</span> <span class="c1">// but we never told the web stack to use Autofac as the</span> <span class="c1">// service provider.</span> <span class="c1">// this means that the minimal API will never be able to</span> <span class="c1">// find services off the container. we would need to resolve</span> <span class="c1">// them BEFORE the API is called, like in this registration</span> <span class="c1">// method itself, from the context that is passed in.</span> <span class="c1">//DependencyA dependencyA = ctx.Resolve&lt;DependencyA&gt;();</span> <span class="c1">// FIXME: But... What happens if something wants to take a</span> <span class="c1">// dependency on the WebApplication instance itself? Once the</span> <span class="c1">// web application has been built, there's no more adding</span> <span class="c1">// dependencies to it!</span> <span class="kt">var</span> <span class="n">summaries</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"Freezing"</span><span class="p">,</span> <span class="s">"Bracing"</span><span class="p">,</span> <span class="s">"Chilly"</span><span class="p">,</span> <span class="s">"Cool"</span><span class="p">,</span> <span class="s">"Mild"</span><span class="p">,</span> <span class="s">"Warm"</span><span class="p">,</span> <span class="s">"Balmy"</span><span class="p">,</span> <span class="s">"Hot"</span><span class="p">,</span> <span class="s">"Sweltering"</span><span class="p">,</span> <span class="s">"Scorching"</span> <span class="p">};</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span> <span class="s">"/weatherforecast"</span><span class="p">,</span> <span class="p">(</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyA</span> <span class="n">dependencyA</span> <span class="p">,</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyB</span> <span class="n">dependencyB</span> <span class="p">,</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyC</span> <span class="n">dependencyC</span> <span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">forecast</span> <span class="p">=</span> <span class="n">Enumerable</span> <span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">5</span><span class="p">)</span> <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">index</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">WeatherForecast</span> <span class="p">(</span> <span class="n">DateOnly</span><span class="p">.</span><span class="nf">FromDateTime</span><span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="nf">AddDays</span><span class="p">(</span><span class="n">index</span><span class="p">)),</span> <span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(-</span><span class="m">20</span><span class="p">,</span> <span class="m">55</span><span class="p">),</span> <span class="n">summaries</span><span class="p">[</span><span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(</span><span class="n">summaries</span><span class="p">.</span><span class="n">Length</span><span class="p">)]</span> <span class="p">))</span> <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span> <span class="k">return</span> <span class="n">forecast</span><span class="p">;</span> <span class="p">});</span> <span class="k">return</span> <span class="n">app</span><span class="p">;</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyA</span><span class="p">(</span> <span class="n">WebApplicationBuilder</span> <span class="n">_webApplicationBuilder</span><span class="p">);</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyB</span><span class="p">(</span> <span class="n">WebApplication</span> <span class="n">_webApplication</span><span class="p">);</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyC</span><span class="p">(</span> <span class="n">IConfiguration</span> <span class="n">_configuration</span><span class="p">);</span> </code></pre> </div> <p>One callout of this approach is that using the Autofac <code>ContainerBuilder</code> class as our primary dependency container affords us the opportunity to structure our entry point to just:</p> <ul> <li><p>Container creation</p></li> <li><p>Dependency registration</p></li> <li><p>Primary dependency resolution</p></li> <li><p>… Call a single method to start the app up!</p></li> </ul> <p>This is, in my opinion, ideal application startup code. Why? Because you never need to come back here to touch it. Ever. No matter how many things you add in! And that’s all because you can scan assemblies to load more modules.</p> <p>Again, this is a personal preference of mine and I am not trying to claim this should be everyone’s goal.</p> <h3> <strong>The Flaws of Autofac ContainerBuilder in ASP.NET Core</strong> </h3> <p>Of course, another approach that isn’t quite bulletproof. So let’s discuss what we DON’T get with this setup of Autofac:</p> <ul> <li><p>Service-resolved parameters passed on minimal APIs simply don’t work. The <code>WebApplication</code> that was built is not configured to use Autofac as the dependency injection framework!</p></li> <li><p>Like the previous article, we still can’t get the <code>WebApplication</code> instance on the dependency container… So we didn’t make any advancements specifically on accessing that.</p></li> </ul> <p>But that’s mostly it! It’s not a terrible list of drawbacks, but the Autofac ContainerBuilder approach was not a silver bullet solution for us. So what did we get out of it? <a href="proxy.php?url=https://youtu.be/FJziGcvuzmo" rel="noopener noreferrer">This video on Autofac</a> will also help explain:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/FJziGcvuzmo"> </iframe> </p> <h3> <strong>The Benefits of Autofac ContainerBuilder in ASP.NET Core</strong> </h3> <p>Pros and cons for everything we do! Now that we’ve seen the issues with Autofac ContainerBuilder in ASP.NET Core, it’s time to look at what advancements we got out of this:</p> <ul> <li><p>We can still access the <code>WebApplicationBuilder</code> and <code>IConfiguration</code> instances, so that’s a comparable benefit to using the <code>AutofacServiceProviderFactory</code> approach.</p></li> <li><p>We can get a very streamlined entry point to our program, which I really like to see. Container creation, registration, resolve your entry point method, and that’s all!</p></li> <li><p>Minimal APIs work, but not with dependencies. Still, we can pre-resolve the dependencies the minimal APIs want and pass those in at the time of method registration. See the commented code!</p></li> </ul> <h2> <strong>More Inversion for Plugin-Based ASP.NET Routes?</strong> </h2> <p>We saw that we could register minimal APIs within an Autofac registration method, but unfortunately, we cannot resolve dependencies from the container directly on the minimal API call itself. We could go build a dedicated class like the following that handles route definitions with dependencies being resolved automatically:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">WeatherForecastRoutes</span><span class="p">(</span> <span class="n">DependencyA</span> <span class="n">_dependencyA</span> <span class="c1">// FIXME: still can't depend on this because</span> <span class="c1">// we can't get the WebApplication</span> <span class="c1">//, DependencyB _dependencyB </span> <span class="p">,</span> <span class="n">DependencyC</span> <span class="n">_dependencyC</span><span class="p">)</span> <span class="p">{</span> <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">_summaries</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"Freezing"</span><span class="p">,</span> <span class="s">"Bracing"</span><span class="p">,</span> <span class="c1">// ...</span> <span class="p">};</span> <span class="k">public</span> <span class="n">WeatherForecast</span><span class="p">[]</span> <span class="nf">Forecast</span><span class="p">()</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">forecast</span> <span class="p">=</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">5</span><span class="p">).</span><span class="nf">Select</span><span class="p">(</span><span class="n">index</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">WeatherForecast</span> <span class="p">(</span> <span class="n">DateOnly</span><span class="p">.</span><span class="nf">FromDateTime</span><span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="nf">AddDays</span><span class="p">(</span><span class="n">index</span><span class="p">)),</span> <span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(-</span><span class="m">20</span><span class="p">,</span> <span class="m">55</span><span class="p">),</span> <span class="n">_summaries</span><span class="p">[</span><span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(</span><span class="n">_summaries</span><span class="p">.</span><span class="n">Length</span><span class="p">)]</span> <span class="p">))</span> <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span> <span class="k">return</span> <span class="n">forecast</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>The automatic resolution happens if we have this class AND the dependencies all on the same container. Then it’s just a matter of calling this code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">var</span> <span class="n">weatherForecastRoutes</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WeatherForecastRoutes</span><span class="p">&gt;();</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span><span class="s">"/weatherforecast2"</span><span class="p">,</span> <span class="n">weatherForecastRoutes</span><span class="p">.</span><span class="n">Forecast</span><span class="p">);</span> </code></pre> </div> <p>This still sucks a bit from a plugin perspective because we’d need to go resolve all of the route classes manually just to call the registration code like that — all stemming from the fact that these things can’t resolve their own access to the <code>WebApplication</code> instance.</p> <p>But wait… What if we flip things around? What if we could resolve some interface like <code>IRegisterRoutes</code> and pass in the <code>WebApplication</code> instance?!<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="c1">// NOTE: make sure to register WeatherForecastRouteRegistrar on the</span> <span class="c1">// autofac container as IRegisterRoutes!</span> <span class="k">internal</span> <span class="k">interface</span> <span class="nc">IRegisterRoutes</span> <span class="p">{</span> <span class="k">void</span> <span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">WebApplication</span> <span class="n">app</span><span class="p">);</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">WeatherForecastRouteRegistrar</span><span class="p">(</span> <span class="n">WeatherForecastRoutes</span> <span class="n">_weatherForecastRoutes</span><span class="p">)</span> <span class="p">:</span> <span class="n">IRegisterRoutes</span> <span class="p">{</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">WebApplication</span> <span class="n">app</span><span class="p">)</span> <span class="p">{</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span><span class="s">"/weatherforecast2"</span><span class="p">,</span> <span class="n">_weatherForecastRoutes</span><span class="p">.</span><span class="n">Forecast</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="c1">// TODO: add this to the autofac code where the </span> <span class="c1">// WebApplication instance is built:</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">registrar</span> <span class="k">in</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IRegisterRoutes</span><span class="p">&gt;&gt;())</span> <span class="p">{</span> <span class="n">registrar</span><span class="p">.</span><span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">app</span><span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>Now we don’t even need to care if the <code>WebApplication</code> instance is accessible to our plugins! Maybe the first version wasn’t so limiting after all? Maybe we’re onto something here… But the next article should explain this in more detail.</p> <h2> <strong>Wrapping Up Autofac ContainerBuilder in ASP.NET Core</strong> </h2> <p>In this article, I explored using an Autofac <code>ContainerBuilder</code> explicitly instead of using <code>AutofacServiceProviderFactory</code> as is normally suggested. We saw some similar benefits and drawbacks, but also a different set of things to consider. Each way can offer pros and cons depending on what you’re after in your application.</p> <p>What was interesting was that if we’re trying to work towards plugins, we might not even need to access the <code>WebApplication</code> instance from our plugins at all! If we care about minimal APIs, this might still be limiting… but otherwise, we’re onto an interesting line of thinking!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> webdev dotnet csharp coding AutofacServiceProviderFactory in ASP.NET Core – Problems With Dependency Injection (Part 1) Dev Leader Tue, 07 May 2024 14:00:00 +0000 https://dev.to/devleader/autofacserviceproviderfactory-in-aspnet-core-problems-with-dependency-injection-part-1-44de https://dev.to/devleader/autofacserviceproviderfactory-in-aspnet-core-problems-with-dependency-injection-part-1-44de <p>We have plenty of awesome options for dependency injection when working in ASP.NET Core applications. For the most part, if you’re not building anything super complicated concerning your types or your software architecture, you can get by with the built-in IServiceCollection. However, we can use AutofacServiceProviderFactory in ASP.NET Core to make Autofac our dependency container of choice in our app!</p> <p>In this article, I highlight how to use AutofacServiceProviderFactory in your ASP.NET Core application along with what you can and cannot do with it. Having many options for dependency injection means that we have many pros and cons to analyze!</p> <p>This will be part of a series where I explore dependency resolution with Autofac inside of ASP.NET Core. I'll be sure to include the series below as the issues are published:</p> <ul> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/04/30/autofacserviceproviderfactory-in-asp-net-core-problems-with-dependency-injection-part-1/" rel="noopener noreferrer">Part 1: AutofacServiceProviderFactory in ASP.NET Core - Problems With Dependency Injection</a></p></li> <li><p><a href="proxy.php?url=https://www.devleader.ca/2024/05/02/autofac-containerbuilder-in-asp-net-core-what-you-need-to-know-part-2" rel="noopener noreferrer">Part 2: Autofac ContainerBuilder In ASP.NET Core – What You Need To Know</a></p></li> <li><p><a>Part 3: Autofac ComponentRegistryBuilder in ASP.NET Core - How To Register Dependencies</a></p></li> </ul> <p>At the end of this series, you'll be able to more confidently explore plugin architectures inside of ASP.NET Core and Blazor -- which will be even more content for you to explore. Keep your eyes peeled on <a href="proxy.php?url=https://dometrain.com/author/nick-cosentino?affcode=1115529_nl-teyzg" rel="noopener noreferrer">my Dometrain courses for a more guided approach to these topics later in 2023</a>.</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Dependency Injection: A Primer</strong> </h2> <h3> <strong>What is Dependency Injection</strong> </h3> <p>Dependency Injection (DI) is a <a href="proxy.php?url=https://www.devleader.ca/2023/12/31/the-big-list-of-design-patterns-everything-you-need-to-know/" rel="noopener noreferrer">design pattern</a> used in programming to make software systems easier to develop, test, and maintain. In C#, like in many other programming languages, dependency injection helps to decouple the components of your applications. Ideally, this leads to developing software that is more flexible and extensible.</p> <p>Dependency Injection is about removing the hard-coded dependencies and making it possible to change them, either at runtime or compile time. This can be useful for many reasons, such as allowing a program to use different databases or testing components by replacing them with mock objects.</p> <p>Consider a code example where we create an instance of a car with an engine:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Car</span> <span class="p">{</span> <span class="k">private</span> <span class="k">readonly</span> <span class="n">IEngine</span> <span class="n">_engine</span><span class="p">;</span> <span class="k">public</span> <span class="nf">Car</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// The Car class directly depends on the GasEngine class.</span> <span class="n">_engine</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">GasEngine</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>We can instead “inject” the dependency via the constructor:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Car</span> <span class="p">{</span> <span class="k">private</span> <span class="k">readonly</span> <span class="n">IEngine</span> <span class="n">_engine</span><span class="p">;</span> <span class="c1">// The engine is injected into the car via the constructor</span> <span class="c1">// so now there is no direct dependency on the Engine class,</span> <span class="c1">// but there is a dependency on the IEngine interface</span> <span class="c1">// which has nothing to do with the implementation</span> <span class="k">public</span> <span class="nf">Car</span><span class="p">(</span><span class="n">IEngine</span> <span class="n">engine</span><span class="p">)</span> <span class="p">{</span> <span class="n">_engine</span> <span class="p">=</span> <span class="n">engine</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>We can even use the idea of a “Dependency Container” that helps make this process seem a bit more magical by not requiring us to explicitly create instances of objects by passing in dependencies. Instead, the container allows us to resolve these dependencies. More on that in the next section!</p> <h3> <strong>What is Autofac?</strong> </h3> <p><a href="proxy.php?url=https://www.devleader.ca/2023/08/22/dependency-injection-how-to-start-with-autofac-the-easy-way/" rel="noopener noreferrer">Autofac is a popular inversion of control (IoC) container for .NET</a>. It manages the dependencies between classes by injecting instances where needed, thereby facilitating a more modular and testable codebase. Autofac is used extensively in applications to implement the dependency injection pattern, allowing us to write cleaner, more maintainable code for the reasons I explained in the previous section.</p> <p><a href="proxy.php?url=https://www.devleader.ca/2024/02/23/scrutor-vs-autofac-in-c-what-you-need-to-know/" rel="noopener noreferrer">There are other IoC containers to help us</a> manage and resolve dependencies in our applications, including the built-in IServiceCollection, but Autofac is the one that I am most comfortable using. As .NET has evolved IServiceCollection has become more feature-rich, and with the gap in features between the two closing, Autofac is still one that I like using in my development.</p> <h3> <strong>What is the AutofacServiceProviderFactory in ASP.NET Core?</strong> </h3> <p>The <code>AutofacServiceProviderFactory</code> is a specific component in the Autofac library designed for integrating Autofac with the built-in dependency injection (DI) system in ASP.NET Core. Essentially, it acts as a bridge allowing you to use Autofac as the DI container instead of the default one provided by Microsoft.</p> <p>I’ve written about this before in this article:</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://www.devleader.ca/2024/03/19/autofac-in-asp-net-core-how-to-avoid-this-debugging-nightmare/" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevleader-d2f9ggbjfpdqcka7.z01.azurefd.net%2Fmedia%2F2024%2F03%2FAutofac-In-ASP-NET-Core-How-To-Avoid-This-Debugging-Nightmare.webp" height="450" class="m-0" width="800"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://www.devleader.ca/2024/03/19/autofac-in-asp-net-core-how-to-avoid-this-debugging-nightmare/" rel="noopener noreferrer" class="c-link"> Autofac In ASP NET Core - How To Avoid This Debugging Nightmare </a> </h2> <p class="truncate-at-3"> Learn how to use Autofac in ASP NET Core applications with only a couple of lines of code! Avoid this common problem when setting up dependency injection. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.devleader.ca%2Ffavicon-32x32.png" width="32" height="32"> devleader.ca </div> </div> </div> </div> <h2> <strong>Exploring A Sample ASP.NET Core Application</strong> </h2> <p>I wanted to make sure we had a common application to refer to when I get into more of the technical details of what we do and do not get with <code>AutofacServiceProviderFactory</code>. The following code is the sample weather app we get from Visual Studio when creating a new ASP.NET Core web API, but I’ve modified it slightly to showcase some of the behavior we get with <code>AutofacServiceProviderFactory</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Autofac.Extensions.DependencyInjection</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span> <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span> <span class="n">builder</span><span class="p">.</span><span class="n">Host</span><span class="p">.</span><span class="nf">UseServiceProviderFactory</span><span class="p">(</span><span class="k">new</span> <span class="nf">AutofacServiceProviderFactory</span><span class="p">(</span><span class="n">containerBuilder</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">RegisterInstance</span><span class="p">(</span><span class="n">builder</span><span class="p">)</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplicationBuilder</span><span class="p">&gt;().</span><span class="n">Configuration</span><span class="p">)</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="c1">// FIXME: we can't do this because the WebApplicationBuilder</span> <span class="c1">// the WebApplicationBuilder is responsible for building the</span> <span class="c1">// WebApplication, so we can't do that manually just to add</span> <span class="c1">// it into the container</span> <span class="c1">//containerBuilder</span> <span class="c1">// .Register(ctx =&gt;</span> <span class="c1">// {</span> <span class="c1">// var app = ctx.Resolve&lt;WebApplicationBuilder&gt;().Build();</span> <span class="c1">// app.UseHttpsRedirection();</span> <span class="c1">// return app;</span> <span class="c1">// })</span> <span class="c1">// .SingleInstance();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyA</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyB</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">DependencyC</span><span class="p">&gt;().</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="c1">//containerBuilder</span> <span class="c1">// .RegisterBuildCallback(ctx =&gt;</span> <span class="c1">// {</span> <span class="c1">// // FIXME: this was never registered</span> <span class="c1">// var app = ctx.Resolve&lt;WebApplication&gt;();</span> <span class="c1">// var summaries = new[]</span> <span class="c1">// {</span> <span class="c1">// "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"</span> <span class="c1">// };</span> <span class="c1">// app.MapGet(</span> <span class="c1">// "/weatherforecast",</span> <span class="c1">// (</span> <span class="c1">// [FromServices] DependencyA dependencyA // this will work</span> <span class="c1">// , [FromServices] DependencyB dependencyB // FIXME: this will fail!!</span> <span class="c1">// , [FromServices] DependencyC dependencyC // this will work</span> <span class="c1">// ) =&gt;</span> <span class="c1">// {</span> <span class="c1">// var forecast = Enumerable.Range(1, 5).Select(index =&gt;</span> <span class="c1">// new WeatherForecast</span> <span class="c1">// (</span> <span class="c1">// DateOnly.FromDateTime(DateTime.Now.AddDays(index)),</span> <span class="c1">// Random.Shared.Next(-20, 55),</span> <span class="c1">// summaries[Random.Shared.Next(summaries.Length)]</span> <span class="c1">// ))</span> <span class="c1">// .ToArray();</span> <span class="c1">// return forecast;</span> <span class="c1">// });</span> <span class="c1">// });</span> <span class="p">}));</span> <span class="c1">// FIXME: we can't get the WebApplication into the</span> <span class="c1">// Autofac container, because it's already been built.</span> <span class="c1">// this means if we have anything that wants to take a</span> <span class="c1">// dependency on the WebApplication instance itself, we</span> <span class="c1">// can't resolve it from the container.</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span> <span class="n">app</span><span class="p">.</span><span class="nf">UseHttpsRedirection</span><span class="p">();</span> <span class="kt">var</span> <span class="n">summaries</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"Freezing"</span><span class="p">,</span> <span class="s">"Bracing"</span><span class="p">,</span> <span class="s">"Chilly"</span><span class="p">,</span> <span class="s">"Cool"</span><span class="p">,</span> <span class="s">"Mild"</span><span class="p">,</span> <span class="s">"Warm"</span><span class="p">,</span> <span class="s">"Balmy"</span><span class="p">,</span> <span class="s">"Hot"</span><span class="p">,</span> <span class="s">"Sweltering"</span><span class="p">,</span> <span class="s">"Scorching"</span> <span class="p">};</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span> <span class="s">"/weatherforecast"</span><span class="p">,</span> <span class="p">(</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyA</span> <span class="n">dependencyA</span> <span class="c1">// this will work</span> <span class="p">,</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyB</span> <span class="n">dependencyB</span> <span class="c1">// FIXME: this will fail!!</span> <span class="p">,</span> <span class="p">[</span><span class="n">FromServices</span><span class="p">]</span> <span class="n">DependencyC</span> <span class="n">dependencyC</span> <span class="c1">// this will work</span> <span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">forecast</span> <span class="p">=</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">5</span><span class="p">).</span><span class="nf">Select</span><span class="p">(</span><span class="n">index</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">WeatherForecast</span> <span class="p">(</span> <span class="n">DateOnly</span><span class="p">.</span><span class="nf">FromDateTime</span><span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="nf">AddDays</span><span class="p">(</span><span class="n">index</span><span class="p">)),</span> <span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(-</span><span class="m">20</span><span class="p">,</span> <span class="m">55</span><span class="p">),</span> <span class="n">summaries</span><span class="p">[</span><span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="nf">Next</span><span class="p">(</span><span class="n">summaries</span><span class="p">.</span><span class="n">Length</span><span class="p">)]</span> <span class="p">))</span> <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span> <span class="k">return</span> <span class="n">forecast</span><span class="p">;</span> <span class="p">});</span> <span class="n">app</span><span class="p">.</span><span class="nf">Run</span><span class="p">();</span> <span class="k">internal</span> <span class="k">record</span> <span class="nc">WeatherForecast</span><span class="p">(</span><span class="n">DateOnly</span> <span class="n">Date</span><span class="p">,</span> <span class="kt">int</span> <span class="n">TemperatureC</span><span class="p">,</span> <span class="kt">string</span><span class="p">?</span> <span class="n">Summary</span><span class="p">)</span> <span class="p">{</span> <span class="k">public</span> <span class="kt">int</span> <span class="n">TemperatureF</span> <span class="p">=&gt;</span> <span class="m">32</span> <span class="p">+</span> <span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">TemperatureC</span> <span class="p">/</span> <span class="m">0.5556</span><span class="p">);</span> <span class="p">}</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyA</span><span class="p">(</span> <span class="n">WebApplicationBuilder</span> <span class="n">_webApplicationBuilder</span><span class="p">);</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyB</span><span class="p">(</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;</span> <span class="n">_webApplication</span><span class="p">);</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DependencyC</span><span class="p">(</span> <span class="n">IConfiguration</span> <span class="n">_configuration</span><span class="p">);</span> </code></pre> </div> <p>You should note that I’ve modified the weather API itself to take in 3 dependencies that we want to resolve from the service list. <code>[FromService]</code> is in fact not required here, but it makes the error messages more clear if you were to go run this and want to understand where and why it fails.</p> <p>But wait… why does it fail?! Keep on readin’ and <a href="proxy.php?url=https://youtu.be/pjvtZGJTqHg" rel="noopener noreferrer">follow along with this video on Autofac to find out more</a>:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/pjvtZGJTqHg"> </iframe> </p> <h3> <strong>What Can We Get With AutofacServiceProviderFactory in ASP.NET Core?</strong> </h3> <p>Let’s start off with what we get from this setup because I do think that this is the typical path. To be clear, there’s nothing “wrong” with this approach, but you need to understand where dependencies are registered and resolved, and therefore what works with your container:</p> <ul> <li><p>We have access to the <code>WebApplicationBuilder</code> on the Autofac <code>ContainerBuilder</code> instance. This allows us to have services depending on the app builder instance, which means we can have modules and/or plugins that want to setup information on the app builder or otherwise read state from the app builder.</p></li> <li><p>With that said, we have access to the <code>IConfiguration</code> instance from the <code>WebApplicationBuilder</code> because it’s exposed on the web app builder itself.</p></li> <li><p>We get the ability to resolve dependencies from the container that are defined directly on our minimal APIs! In the example I shared above, the dependency classes A through C are all types that can be resolved from the container automatically on the minimal API. There’s a catch for one of these which we’ll cover, but the point is their registrations can be seen by our minimal API.</p></li> </ul> <p>In general, this is probably “good enough” for most situations if you just want to use Autofac for your ASP.NET Core application. However, this is limiting for the style of development that I like to do.</p> <h3> <strong>What’s Missing With AutofacServiceProviderFactory in ASP.NET Core?</strong> </h3> <p>Now that we’ve seen the goodness that we get, let’s discuss where there are some drawbacks. They’re essentially already highlighted in the code with FIXME comments, but it’s worth elaborating on them in more detail here. Again, this is not to suggest this is the “wrong” way to do it, just that you have some considerations to make:</p> <ul> <li><p>The <code>WebApplication</code> instance is not something that we can resolve from the container. That is, if you ever want to have classes automatically resolve from the dependency container, they cannot take a dependency on <code>WebApplication</code>. This is because this instance is never registered onto the container and therefore cannot be automatically injected for us.</p></li> <li><p>We can’t overcome this behavior by calling the <code>Build()</code> method manually on the <code>WebApplicationBuilder</code> inside of an Autofac registration. This is because the chain of registrations executes once we call <code>Build()</code> on the web application builder OUTSIDE of the container, which then handles the rest of the application being built. Said another way, this creates a bit of a circular dependency on the responsibilities that need to be handled.</p></li> <li><p>Because we cannot resolve the <code>WebApplication</code> instance from the dependency container, we cannot create plugins that add their own routes to the application using the minimal API route registration syntax. If this is indeed possible to do, it would have to be using a different API and instance of a different type since the <code>WebApplication</code> instance is not accessible to us via the container.</p></li> <li><p>Based on the above points, we cannot have dependencies on the routes like <code>DependencyB</code> in the example above. This is because this type has a dependency on <code>WebApplication</code> and the container simply does not know about it. In the future articles, you’ll see examples of this pattern coming up again so it’s worth mentioning in this article for reference.</p></li> </ul> <p>Many of these are not a concern for folks building typical applications. However, as someone that builds mostly plugin architecture applications, this is very limiting for me!</p> <h2> <strong>Wrapping Up AutofacServiceProviderFactory in ASP.NET Core</strong> </h2> <p>In this article, I provided a brief overview of dependency injection and Autofac within ASP.NET Core. The primary takeaway was looking at what you do and do not get when using AutofacServiceProviderFactory in ASP.NET Core. While the limitations of this are minimized for the average application, this does not work well for a plugin architecture that wants to extend the API routes via plugins.</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> webdev dotnet csharp programming Break into Big Tech – My Journey from Startup to Microsoft Dev Leader Mon, 06 May 2024 14:00:00 +0000 https://dev.to/devleader/break-into-big-tech-my-journey-from-startup-to-microsoft-ab0 https://dev.to/devleader/break-into-big-tech-my-journey-from-startup-to-microsoft-ab0 <p>Many software engineers set their sights on getting into big tech someday — It seems like <em>the</em> destination to end up at in one’s career. Now this of course isn’t universally true (nor should it be) but regardless, this is a goal for many. But is Big Tech all it’s cracked up to be? Are the stereotypes true? How the heck can someone get into these big companies?</p> <p>In this article, I wanted to share with you my journey from working at startup companies all the way to being a Principal Software Engineering Manager at Microsoft. I’d love to share with you my interview experiences and my observations about what I value (and what I dislike) from startups and Big Tech.</p> <p>Remember that your <a href="proxy.php?url=https://www.devleader.ca/2024/01/19/owning-your-career-journey-behind-the-screen-2024-january-week-3/" rel="noopener noreferrer">career journey</a> is for you to own. Don’t try to copy someone else’s life, just learn from their experiences and take charge of your own. There’s no “wrong” path. Every path is unique.</p> <p>I wrote this article for my good friend, <a href="proxy.php?url=https://www.linkedin.com/in/mwaseemzakir/" rel="noopener noreferrer">Muhammad Waseem</a>. He graciously offered to include my story <a href="proxy.php?url=https://mwaseemzakir.substack.com/p/ep-56-break-into-big-tech-journey" rel="noopener noreferrer">in one of his newsletters</a>, and I thought it would be such an awesome opportunity to share with his audience. My version of the article has been slightly adapted so I can share other relevant content for my own audience.</p> <p>Muhammad, my friend, thank you for thinking about me!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> &lt;div class="color-secondary fs-s flex items-center"&gt; &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://substackcdn.com/image/fetch/$s_!zfLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a947694-4ddd-4cc0-befa-83c12c83141d%2Ffavicon.ico" loading="lazy" /&gt; weekly.devleader.ca &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> </div> </div> <br> <h2> <strong>My Background</strong> </h2> <p>I went to the University of Waterloo for computer engineering. While I didn’t like my classes at all, my 6 internships really solidified that I wanted to be in this industry. I spent my internships mostly at startups or small companies, but in completely different sectors so I could get different experiences.</p> <blockquote> <p><em>Action: Take advantage of internships if you have the option!</em></p> <p><em>Action: Use your internships to explore different domains and styles of companies!</em></p> </blockquote> <p>My first real full-time software engineering job outside of university was a digital forensics company, now called <a href="proxy.php?url=https://www.magnetforensics.com/" rel="noopener noreferrer">Magnet Forensics</a>, that was just starting out. This was the first time I started to have a good mix of autonomy and solid leadership mixed together because up until this point with work, I felt it hard to stay motivated in what I was doing for work.</p> <p>This company had also taken a chance on me because they appreciated my existing skills and way of thinking but knew that I had zero experience in digital forensics. This was also going to be one of the first times in my career that I really noticed “Oh crap, I don’t know how to do any of this…” only to realize that after several months I was on my way to building expertise.</p> <blockquote> <p><em>Action: Find companies and leadership that you align with. This may take time and experience in industry.</em></p> <p><em>Action: Don’t be afraid to jump into new challenges. It’s the best way to learn.</em></p> </blockquote> <p>I became a technical manager within several months of being at this company, which required my time was spent coding and managing. But this was all due to one critical software engineering skill that I think everyone should invest more time in: Communication.</p> <blockquote> <p><em>Action: Work on your</em> <a href="proxy.php?url=https://www.devleader.ca/2024/01/18/software-engineering-soft-skills-6-focus-areas-that-you-need/" rel="noopener noreferrer"><em>soft skills, not just your technical skills</em></a></p> </blockquote> <p><a href="proxy.php?url=https://youtu.be/AWTwji6mmeA" rel="noopener noreferrer">Check out this video with Callie Buruchara for more details on why communication is so valuable</a>:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/AWTwji6mmeA"> </iframe> </p> <h2> <strong>Getting into Big Tech</strong> </h2> <p>This was one of my least favorite things I’ve done in the past few years. I find that I don’t do a great job selling myself to recruiters, and it feels unnatural to discuss my accomplishments. I needed to spend time updating my resume, which would include <a href="proxy.php?url=https://www.devleader.ca/2024/01/06/brag-documents-highlight-trackers-take-control-of-your-career-progression/" rel="noopener noreferrer">highlighting some of the biggest accomplishments in my career</a> up to this point.</p> <blockquote> <p><em>Action: Update your resume with high impact work. Pick relevant experiences to what you’re applying for.</em></p> </blockquote> <p>I applied to some of the popular Big Tech companies and after several <a href="proxy.php?url=https://www.devleader.ca/2024/03/30/actionable-interview-tips-dev-leader-weekly-37/" rel="noopener noreferrer">weeks had interviews</a> that were lined up over a few weeks. In order to do this, I chose the route of going onto their career pages and going through the typical paths. I felt that I had solid work experience and based on historically what I had heard, it shouldn’t be too difficult to hear back.</p> <blockquote> <p><em>Action: Most (if not all) companies have career pages that show you what they are actively hiring for. Use those.</em></p> </blockquote> <p>Admittedly, the job market now is extremely different than it was when I was applying. You need to do everything you can to stand out. This may be an EXTREMELY difficult time to apply to Big Tech companies because of the volume of people trying — so I do not want you to be discouraged. It may not currently be in your favor, but that doesn’t mean you can’t focus on things that are in your control.</p> <blockquote> <p><em>Action: Give some consideration to companies that aren’t Big Tech. They can offer incredible opportunities and there’s less competition.</em></p> </blockquote> <p>Networking can be very powerful — so get in touch with recruiters as much as you can. You may have luck connecting with hiring managers, but from my personal experience, I have to direct every single person to the Microsoft careers page anyway.</p> <blockquote> <p><em>Action: Always try to be networking! Build relationships with recruiters!</em></p> </blockquote> <p>With that said, if you’re interested in Microsoft, my biggest advice would be to:</p> <ul> <li><p>Use <a href="proxy.php?url=https://careers.microsoft.com/v2/global/en/home.html" rel="noopener noreferrer">the Microsoft careers page</a> to find jobs you’re interested in</p></li> <li><p>Use LinkedIn to connect with recruiters</p></li> <li><p>Use LinkedIn to connect with employees in the space</p></li> </ul> <p>When you connect with the employees in the space DO NOT ask them to refer you. They don’t even know you, so they should not be referring you. Instead, see if you can get some time from them to <a href="proxy.php?url=https://www.devleader.ca/2023/09/27/workplace-based-learning-how-to-balance-learning-at-work-vs-home/" rel="noopener noreferrer">learn about what it’s like working</a> in that space. Build a true connection and use it as a learning opportunity.</p> <h3> <strong>Interviewing – Exactly What You’d Expect</strong> </h3> <p>I’m an <a href="proxy.php?url=https://www.devleader.ca/2023/03/13/hands-on-management-how-to-lead-engineers-to-success/" rel="noopener noreferrer">engineering manager and I was applying for engineering manager</a> roles… But you bet that I was still being interviewed like a Principal-level software <a href="proxy.php?url=https://www.devleader.ca/2023/03/13/hands-on-management-how-to-lead-engineers-to-success/" rel="noopener noreferrer">engineer AND with management</a> components added in. There are many similarities with how I would be interviewed compared to an individual contributor software engineer!</p> <p>I was grinding LeetCode questions every day. Systems <a href="proxy.php?url=https://www.devleader.ca/2023/12/13/what-is-the-adapter-design-pattern-beginner-questions-answered/" rel="noopener noreferrer">design questions</a>. Behavioral questions. All of it. Every day for multiple hours. This was extreme for me because I hadn’t interviewed in nearly a DECADE. And every single big tech company was similar. Algorithms. Systems design. Behavioral. Much of what you read or hear online about this is spot on.</p> <blockquote> <p><em>Action: Familiarize yourself with coding questions (LeetCode), distributed</em> <a href="proxy.php?url=https://www.devleader.ca/2023/12/13/what-is-the-adapter-design-pattern-beginner-questions-answered/" rel="noopener noreferrer"><em>design questions, and project/behavioral questions</em></a></p> <p><em>Action: Set aside time to practice as much as you can.</em></p> </blockquote> <p>You need to be prepared to ask clarifying questions in the technical part. I hate these types of technical interview questions because I’ve seen people practice them like crazy, get hired, and then struggle as a developer because they just managed to train themselves well at interviewing. Something to keep in mind.</p> <blockquote> <p><em>Action: When you’re practicing, try verbally asking clarifying questions and give yourself some constraints. You need to get good at this.</em></p> </blockquote> <p>I only had one of my interviews, but that’s okay. It can happen to anyone. Ultimately, I chose Microsoft because everything I had heard about the work culture was aligned with what I wanted.</p> <p>These two livestreams focus on getting noticed and preparing for interviews, and I think they’re very valuable to go alongside this:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/7EIcqeNeTGA"> </iframe> </p> <p>And the second one focusing on the interview process itself, here:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/6ckNmAAtjs8"> </iframe> </p> <h2> <strong>Big Tech – Final Thoughts</strong> </h2> <p>I want to close out this article by bringing back what I said in the introduction:</p> <p>There’s no “wrong” path. Every path is unique.</p> <p>My philosophy in software engineering is that there are pros and cons to everything. Where we work is no different. Some similarities and differences from my own experiences:</p> <ul> <li><p>You might be working on platforms and/or internal systems compared to user-facing offerings. Figure out what you prefer!</p></li> <li><p>You can find a lot of meaning in what you’re doing at big or small companies, but it’s often easier to feel that you have a bigger relative impact at a smaller company</p></li> <li><p>How much autonomy you have can vary from company to company — usually smaller companies there’s more flexibility and autonomy because there’s less bureaucracy built in.</p></li> <li><p>From team to team, or company to company, you might notice the rate at which you can ship features/fixes is different. This can be a VERY big quality of life to consider as a software engineer.</p></li> <li><p>Big tech has very ironed out career ladders whereas startups it can be more chaotic — but your level vs how much REAL experience you gain are not always aligned.</p></li> <li><p>How you interview for Big Tech is well documented but for startups and smaller companies the interview processes may look quite different</p></li> </ul> <p>There are many more things to compare — but I want you to know that many people will value these things differently. What we value in life changes as well. I’m very respectful of my work-life time boundaries now. No more 16-hour days.</p> <p>But a question I’d leave you with is… What do you truly value in your career? In your life?</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> &lt;div class="color-secondary fs-s flex items-center"&gt; &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://substackcdn.com/image/fetch/$s_!zfLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a947694-4ddd-4cc0-befa-83c12c83141d%2Ffavicon.ico" loading="lazy" /&gt; weekly.devleader.ca &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> </div> </div> <br> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> </div> </div> </div> </div> career startup watercooler coding MudBlazor with Blazor Interactive SSR – What You Need To Know Dev Leader Wed, 01 May 2024 16:00:00 +0000 https://dev.to/devleader/mudblazor-with-blazor-interactive-ssr-what-you-need-to-know-28i9 https://dev.to/devleader/mudblazor-with-blazor-interactive-ssr-what-you-need-to-know-28i9 <p>This is yet another selfish guide! I’m writing this to help my future self with having MudBlazor with Blazor interactive SSR working within a new project. Of course, the positive side effect is that you get to benefit from this guide too! Maybe it wasn’t so selfish after all, right?!</p> <p>This guide will focus on getting MudBlazor with Blazor interactive SSR set up and configured in a new Blazor project in dotnet 8. This is hopefully applicable for future versions of dotnet, as long as this doesn’t change behavior dramatically. Following this guide will ideally prevent you from running into <a href="proxy.php?url=https://www.devleader.ca/2024/03/21/blazor-render-mode-how-to-avoid-dependency-injection-woes/" rel="noopener noreferrer">all sorts of fun Blazor render mode issues</a>.</p> <h2> <strong>What is MudBlazor?</strong> </h2> <p>Like with all user-interface tech stacks, it’s very common to have reusable control libraries. One such control library is <a href="proxy.php?url=https://mudblazor.com/" rel="noopener noreferrer">MudBlazor</a>. In their own words:</p> <blockquote> <p><em>MudBlazor is an ambitious Material Design component framework for Blazor with an emphasis on ease of use and clear structure. It is perfect for .NET developers who want to rapidly build web applications without having to struggle with CSS and Javascript. MudBlazor, being written entirely in C#, empowers you to adapt, fix or extend the framework. There are plenty of examples in the documentation, which makes understanding and learning MudBlazor very easy.</em></p> </blockquote> <p>Originally, I went looking for MudBlazor because I wanted to develop more of a <a href="proxy.php?url=https://www.devleader.ca/2024/03/20/mudblazor-list-items-how-to-create-awesome-blazor-list-views/" rel="noopener noreferrer">customized list view in my application</a>. However, the default controls didn’t seem like they did a great job for what I wanted. I’ve spent well over a decade building user interface applications in WinForms and WPF, so I’m no stranger to control libraries. But that’s exactly why I figured I shouldn’t need to roll my own — someone else has got this covered!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>What Are Blazor Render Modes?</strong> </h2> <p>Blazor Web Apps use different render modes to control where and how components are rendered. The modes include:</p> <ol> <li><p><strong>Static Server</strong>: Renders components on the server without interactivity.</p></li> <li><p><strong>Interactive Server</strong>: Also renders on the server but allows interactivity using Blazor Server.</p></li> <li><p><strong>Interactive WebAssembly</strong>: Renders interactively on the client-side using Blazor WebAssembly.</p></li> <li><p><strong>Interactive Auto</strong>: Starts with server-side rendering and shifts to client-side on subsequent interactions after the Blazor bundle is downloaded.</p></li> </ol> <p>These render modes are set using the <code>@rendermode</code> directive in the component’s code. More details on configuring and applying these modes can be found on the <a href="proxy.php?url=https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-8.0" rel="noopener noreferrer">Microsoft documentation page</a>.</p> <p>This article is not focusing on which render mode is better or worse, nor will I be doing an in-depth analysis. I wanted to provide this context so that you can see we’ll be using Interactive Server render mode to get Blazor server-side rendering (SSR) with our app.</p> <p>With that said, the distinction between client-side and server-side rendering is important for performance and interactivity:</p> <ul> <li><p><strong>Client-side rendering</strong> (WebAssembly mode): Components are executed and rendered directly in the user’s browser using WebAssembly. This mode offers a richer, more interactive experience as it doesn’t require a round-trip to the server for UI updates. However, it involves a larger initial download and more resource consumption on the client side.</p></li> <li><p><strong>Server-side rendering</strong> (Server mode): Components are executed and rendered on the server. The rendered UI is delivered as static HTML to the client’s browser, and interactivity is maintained through a SignalR connection that manages event handling and UI updates. This mode minimizes client-side resources since the client doesn’t execute the component logic, but it relies heavily on the network connection to the server, which can impact responsiveness and user experience.</p></li> </ul> <p>Each mode has its use case depending on the application’s needs for performance, scalability, and complexity. The focus of this article is on a server rendering mode not because I claim it’s superior, but because it’s what I needed for my own development purposes.</p> <h2> <strong>How to Get MudBlazor with Blazor Interactive SSR Working</strong> </h2> <p>The following sections will give you the step-by-step actions required to get MudBlazor with Blazor interactive SSR working. You can follow along with <a href="proxy.php?url=https://www.youtube.com/watch?v=TxLc7cauJRg" rel="noopener noreferrer">this MudBlazor video tutorial as well</a>:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/TxLc7cauJRg"> </iframe> </p> <h3> <strong>New Blazor Project Setup</strong> </h3> <p>The first thing that we need to do is create our project in Visual Studio. To do that, we’re going to select the “Blazor Web App” project template from Visual Studio.</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprja00mql5mf2jpsa00d.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprja00mql5mf2jpsa00d.png" alt="MudBlazor with Blazor SSR - New Blazor Web App" width="800" height="554"></a></p> <p>Next, we’ll want to ensure we select the correct render mode. We want it to be “Server” as we see in the screenshot below.</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixt6z59ixucnxqn9g1t6.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixt6z59ixucnxqn9g1t6.png" alt="MudBlazor with Blazor SSR - Server Render Mode" width="800" height="561"></a></p> <p>The other options are of course up to you. If indeed you need another render mode, then the rest of this guide is not for you as we’re strictly focused on server-side render (SSR) mode. Remember, the reason that I wrote this is that I thought I <em>had</em> to use the dual mode for supporting MudBlazor because the instructions I received didn’t seem to line up exactly.</p> <h3> <strong>Configuring Mud Blazor with Blazor Interactive SSR</strong> </h3> <p>Now that we have our project setup, it’s time to get going with setting up MudBlazor. I should note that they DO have instructions that you can follow <a href="proxy.php?url=https://github.com/MudBlazor/MudBlazor" rel="noopener noreferrer">on their GitHub</a> — so if you’re getting stuck with my guide, go read theirs. However, I followed theirs the first time and still ran into some fun hiccups because I didn’t know what project to create. Not the fault of MudBlazor nor the fault of Blazor; Just Nick’s fault.</p> <p>Step one will be getting the nuget package installed:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="n">dotnet</span> <span class="k">add</span> <span class="n">package</span> <span class="n">MudBlazor</span> </code></pre> </div> <p>And once installed, we only have a couple of spots to go update! Starting off, to make the MudBlazor accessible in our razor files by default, we can add the following to <code>_Imports.razor</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="n">@using</span> <span class="n">MudBlazor</span> </code></pre> </div> <p>Slightly separate guidance from what they list on their GitHub, but we can place the following code in the &lt;head&gt; block of App.razor<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="p">&lt;</span><span class="n">link</span> <span class="n">href</span><span class="p">=</span><span class="s">"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap"</span> <span class="n">rel</span><span class="p">=</span><span class="s">"stylesheet"</span> <span class="p">/&gt;</span> <span class="p">&lt;</span><span class="n">link</span> <span class="n">href</span><span class="p">=</span><span class="s">"_content/MudBlazor/MudBlazor.min.css"</span> <span class="n">rel</span><span class="p">=</span><span class="s">"stylesheet"</span> <span class="p">/&gt;</span> <span class="p">&lt;</span><span class="n">MudThemeProvider</span><span class="p">/&gt;</span> <span class="p">&lt;</span><span class="n">MudDialogProvider</span><span class="p">/&gt;</span> <span class="p">&lt;</span><span class="n">MudSnackbarProvider</span><span class="p">/&gt;</span> </code></pre> </div> <p>Next, we add the following to the &lt;body&gt; block of the same file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="p">&lt;</span><span class="n">script</span> <span class="n">src</span><span class="p">=</span><span class="s">"_content/MudBlazor/MudBlazor.min.js"</span><span class="p">&gt;&lt;/</span><span class="n">script</span><span class="p">&gt;</span> </code></pre> </div> <p>And finally, we need these two lines into program.cs to enable dependency injection for MudBlazor:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">MudBlazor.Services</span><span class="p">;</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddMudServices</span><span class="p">();</span> </code></pre> </div> <h2> <strong>Using MudBlazor with Blazor Interactive SSR</strong> </h2> <p>Now that we’re all configured, we can use MudBlazor! I started off with the sample application to prove this all out, so I figured I’d change the default “counter” page to use MudBlazor controls.</p> <p>Here’s the change to that code that I made:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="n">@page</span> <span class="s">"/counter"</span> <span class="p">&lt;</span><span class="n">PageTitle</span><span class="p">&gt;</span><span class="n">Counter</span><span class="p">&lt;/</span><span class="n">PageTitle</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="n">h1</span><span class="p">&gt;</span><span class="n">Counter</span><span class="p">&lt;/</span><span class="n">h1</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="n">MudText</span> <span class="n">Typo</span><span class="p">=</span><span class="s">"Typo.h6"</span><span class="p">&gt;</span> <span class="n">Current</span> <span class="n">count</span><span class="p">:</span> <span class="n">@currentCount</span> <span class="p">&lt;/</span><span class="n">MudText</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="n">MudButton</span> <span class="n">Variant</span><span class="p">=</span><span class="s">"Variant.Filled"</span> <span class="n">Color</span><span class="p">=</span><span class="s">"Color.Primary"</span> <span class="n">OnClick</span><span class="p">=</span><span class="s">"ButtonOnClick"</span><span class="p">&gt;</span> <span class="n">Click</span> <span class="n">Me</span><span class="p">!</span> <span class="p">&lt;/</span><span class="n">MudButton</span><span class="p">&gt;</span> <span class="n">@code</span> <span class="p">{</span> <span class="k">private</span> <span class="kt">int</span> <span class="n">currentCount</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="k">void</span> <span class="nf">ButtonOnClick</span><span class="p">()</span> <span class="p">{</span> <span class="n">currentCount</span><span class="p">++;</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>And if you want to see it in action:</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsel467uopt1de4mcath.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsel467uopt1de4mcath.png" alt="MudBlazor with Blazor SSR - Counter Page" width="800" height="474"></a></p> <h2> <strong>Wrapping Up MudBlazor with Blazor Interactive SSR</strong> </h2> <p>This was just a simple guide to get you up and running using MudBlazor with Blazor interactive SSR! If you start off with the Blazor server-side rendering project instead of the dual mode where it’s auto server and webassembly, you’ll have a much better time. However, maybe you know what you’re doing significantly better than me and you’re ready to jump into the dual render-mode support — but I certainly was not!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> blazor webdev dotnet csharp Try Catch in C#: The Basics You Need to Know Dev Leader Tue, 30 Apr 2024 16:00:00 +0000 https://dev.to/devleader/try-catch-in-c-the-basics-you-need-to-know-13jo https://dev.to/devleader/try-catch-in-c-the-basics-you-need-to-know-13jo <p>As much as we’d like to write perfect programs, there’s going to be a point where you need to think about handling error cases in your C# applications. That’s why you’re here: for an introduction to try catch in C#!</p> <p>In this article, I’ll explain the very basics of how to structure try catch blocks and what each block is responsible for. The code is simple and aims to help explain some of the basic <a href="proxy.php?url=https://www.devleader.ca/2024/02/22/c-for-beginners-5-simplified-concepts-in-c/" rel="noopener noreferrer">concepts to beginners</a> working in C#. If that sounds like you, read on!</p> <h2> <strong>Overview of Exception Handling in CSharp</strong> </h2> <p>Let’s face it: there are going to be exceptions in our C# applications and services at some point. We hate to admit it, but it’s a reality that we have to understand how to work with.</p> <p>Exception handling in C# is done by using what’s called a try/catch block. So try catch in C# is how we set up code to have some type of protection and define the logic for how we want to deal with those exceptions.</p> <p>The following sections will explain the two main pieces, try and catch, and later on we’ll see an extra third component we can add to the try catch blocks we create in C#. You can follow along with <a href="proxy.php?url=https://youtu.be/rofX_tAF7e4" rel="noopener noreferrer">this video on how to handle exceptions with try/catch blocks in C# as well</a>:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/rofX_tAF7e4"> </iframe> </p> <h3> <strong>The Try Block</strong> </h3> <p>The try block is the first important part of our exception handling that we need to look at. It serves the purpose of enclosing the code that might potentially throw an exception. By placing the code within a try block, we ensure that any exceptions that occur can be caught and handled appropriately — but it’s not handled by this block, this block just tells us what will get handled.</p> <p>The try block is structured using the keyword “try”, followed by a set of curly braces that contain the code we want to monitor for exceptions. This code is often referred to as the “protected code”, as it is within this block that we anticipate will be potentially throwing exceptions. Here’s an example of a try block in C#:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="c1">// Code that might throw an exception</span> <span class="kt">int</span> <span class="n">result</span> <span class="p">=</span> <span class="nf">Divide</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"The result is: "</span> <span class="p">+</span> <span class="n">result</span><span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>In this example, we have a function called “Divide” that takes two integers as parameters and attempts to perform a division operation. However, if the second parameter is zero, it will throw a divide by zero exception. By enclosing this code within a try block, we can catch and handle this exception appropriately — but we need another block to actually handle it! And that’s where we’re headed in the next section!</p> <h3> <strong>The Catch Block</strong> </h3> <p>The main purpose of the catch block is to provide a mechanism for handling exceptions gracefully. The try block allows us to define what we want to protect, and the catch block allows us to define what we’ll handle and how we’ll handle it.</p> <p>When an exception is thrown, the catch block allows us to specify the actions to be taken in response to that exception. These actions could include logging the exception, displaying an error message to the user, or taking any other necessary corrective measures. The choice is yours!</p> <p>To catch a specific type of exception, we use the catch keyword followed by the exception type we want to handle. This allows us to handle different exceptions in different ways, tailoring our response based on the specific type of exception.</p> <p>Here’s an example of a catch block that handles a specific exception type, in this case, the <code>DivideByZeroException</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">result</span> <span class="p">=</span> <span class="m">10</span> <span class="p">/</span> <span class="m">0</span><span class="p">;</span> <span class="c1">// This will throw a DivideByZeroException</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">DivideByZeroException</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"An error occurred: "</span> <span class="p">+</span> <span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>In this example, the code within the try block attempts to divide the number 10 by 0, which will result in a <code>DivideByZeroException</code>. The catch block catches this exception and executes the code within its block, which in this case, simply writes an error message to the console, displaying the message provided by the exception.</p> <p>You can also use a base exception class or omit the exception portion altogether to catch all (well, almost all) exceptions:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// this will catch all catchable exceptions</span> <span class="p">}</span> <span class="c1">// OR</span> <span class="k">try</span> <span class="p">{</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">{</span> <span class="c1">// note that we don't have an exception instance in this case!</span> <span class="p">}</span> </code></pre> </div> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Handling Multiple Exceptions</strong> </h2> <p>If one exception can be thrown from a called piece of code, odds are that many can. As a result, it’s common to encounter scenarios where multiple types of exceptions can occur within a single try block. These exceptions may arise due to different errors or exceptional situations that need to be handled appropriately. In this section, I’ll discuss how to handle multiple exceptions by using either multiple catch blocks or a single catch block with multiple exception types. Let’s see how!</p> <h3> <strong>Multiple Catch Blocks Approach</strong> </h3> <p>When handling multiple exceptions, one approach is to use multiple catch blocks. Each catch block is responsible for handling a specific type of exception. By using this approach, you can specify separate code blocks to handle different exceptions based on their respective types.</p> <p>Here is an example that demonstrates the multiple catch blocks approach:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="c1">// Code that may throw exceptions</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">ArgumentNullException</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Handle ArgumentNullException</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">DivideByZeroException</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Handle DivideByZeroException</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">FormatException</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Handle FormatException</span> <span class="p">}</span> </code></pre> </div> <p>In the above example, the catch block following the try block will catch and handle any <code>ArgumentNullException</code> that occurs. Similarly, the catch blocks for <code>DivideByZeroException</code> and <code>FormatException</code> will handle their respective exceptions.</p> <h3> <strong>Single Catch Block with When Filtering</strong> </h3> <p>Another approach for handling multiple exceptions is to use a single catch block that can handle multiple exception types. This approach can be useful when you want to handle multiple exceptions in the same way without writing separate catch blocks for each one.</p> <p>Here is an example that demonstrates the single catch block approach:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="c1">// Code that may throw exceptions</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="k">when</span> <span class="c1">// look at this fancy keyword!</span> <span class="p">(</span> <span class="n">ex</span> <span class="k">is</span> <span class="n">ArgumentNullException</span> <span class="p">||</span> <span class="n">ex</span> <span class="k">is</span> <span class="n">DivideByZeroException</span> <span class="p">||</span> <span class="n">ex</span> <span class="k">is</span> <span class="n">FormatException</span> <span class="p">)</span> <span class="p">{</span> <span class="c1">// Handle ArgumentNullException, DivideByZeroException, and FormatException</span> <span class="p">}</span> </code></pre> </div> <p>In the above example, the catch block will handle any <code>ArgumentNullException</code>, <code>DivideByZeroException</code>, or <code>FormatException</code> that occurs within the try block. This is because we’ve placed a filter onto the exception handler using the <code>when</code> keyword!</p> <p>I should note that you can do more filtering than just type-checking with the when keyword. You’re able to examine the different properties for the exception instance and create filters accordingly. If you needed to filter by a certain exception message or error code on a particular exception type, you can do that with the <code>when</code> keyword.</p> <h2> <strong>The Finally Block</strong> </h2> <p>The finally block in C# is used to define a section of code that will always be executed, regardless of whether an exception occurred or not. Its purpose is to ensure that certain tasks, such as releasing resources or performing cleanup operations, are always carried out, regardless of the outcome of the try block.</p> <p>The finally block is executed after the try and catch blocks, whether an exception is thrown or not. It’s written with the keyword “finally” followed by a set of curly braces {}. Any code within these braces will be executed immediately after the catch block finishes.</p> <h3> <strong>Finally Block Use Case</strong> </h3> <p>One common use case for the finally block is to release any resources that were acquired within the try block. This could include closing file handles, database connections, network sockets, or any other resource that needs to be freed up. By placing the cleanup code in the finally block, you can ensure that it will be executed even if an exception is thrown in the try block.</p> <p>Here is an example that demonstrates the use of the finally block for resource cleanup:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">try</span> <span class="p">{</span> <span class="c1">// Code that could potentially throw an exception</span> <span class="c1">// Acquiring resources</span> <span class="c1">// Performing operations</span> <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Exception handling code</span> <span class="c1">// Logging or displaying error messages</span> <span class="p">}</span> <span class="k">finally</span> <span class="p">{</span> <span class="c1">// Code to release resources</span> <span class="c1">// Closing file handles, database connections, etc.</span> <span class="p">}</span> </code></pre> </div> <p>In this example, if an exception is thrown in the try block, the program flow will jump to the catch block to handle the exception. However, regardless of whether an exception is thrown or not, the code within the finally block will always be executed afterwards. This ensures that any acquired resources are properly released, preventing resource leaks and maintaining the stability of the program.</p> <h3> <strong>Alternative to Finally Blocks: IDisposable</strong> </h3> <p>The finally block that we can use when it comes to try catch in C# is very helpful — but try/catch syntax is already a bit clunky to begin with. It’s a common pattern that we want to clean up resources and if we’re being defensive, we want to make sure that we clean them up even when we have error scenarios.</p> <p>We can use the <code>IDisposable</code> interface and a using block to help support this. So instead of requiring a finally block to clean things up, you could have code inside of a <code>Dispose()</code> method on the object that implements <code>IDisposable</code>. The code would be simplified to this:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">MyClass</span> <span class="p">:</span> <span class="n">IDisposable</span> <span class="p">{</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// TODO: do your cleanup... same </span> <span class="c1">// stuff that you might have wanted</span> <span class="c1">// in your finally block!</span> <span class="p">}</span> <span class="p">}</span> <span class="k">using</span> <span class="p">(</span><span class="n">Myclass</span> <span class="n">myClass</span> <span class="p">=</span> <span class="k">new</span><span class="p">())</span> <span class="p">{</span> <span class="c1">// do stuff with myClass</span> <span class="p">}</span> <span class="c1">// dispose runs after we leave the block</span> </code></pre> </div> <p>This is a lot less clunky, in my opinion than a whole try/finally block to support cleanup — but of course, this will not catch errors just ensure you can still run cleanup code. We can simplify this further with implicit using now where the <code>Dispose()</code> method runs when the variable goes out of scope:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">public</span> <span class="k">void</span> <span class="nf">SomeMethod</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// implicit using...</span> <span class="k">using</span> <span class="nn">Myclass</span> <span class="n">myClass</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> <span class="c1">// do stuff with myClass</span> <span class="c1">// dispose runs at the end here since the variable goes out of scope</span> <span class="p">}</span> </code></pre> </div> <h2> <strong>Considerations for Try Catch in CSharp</strong> </h2> <p>Now that you’ve seen several different ways we can use try catch in C# as well as some different use cases, let’s talk about some considerations. We’ve seen the tools we have to use, but some guidance on using them appropriately seems fitting:</p> <ol> <li><p>Is it REALLY exceptional?: Consider if the exception you’re catching is truly exceptional. Unfortunately, many libraries and programs have exceptions thrown that are not truly exceptional behavior for an application. This can complicate logic and slow things down. So if you don’t need to throw them, don’t. But you also might need to catch them because you don’t want the entire program to terminate.</p></li> <li><p>Catch All vs Catch Specific: Many people frown upon using a try/catch block that attempts to catch all exceptions. The argument is that you could be masking an underlying problem with a blanket handler. However, there are absolutely situations (many of which I’ve used in a professional setting) where we’ve been better off with a catch-all. Some things we are calling are outside of our control with respect to the errors they throw, and if you don’t need your entire application or service to end… then you need to handle them.</p></li> <li><p>Proper Cleanup: Consider if you need something like a finally block or to use the dispose pattern. Remember, using the dispose pattern can help clean up the code but alone it does not prevent exceptions from being thrown.</p></li> <li><p>Logging &amp; Telemetry: You’ll not only want to understand recovery patterns when using try catch in C#, but you should consider if you need to be doing something with this error information. If you have a live service running in production, there are many cases where you’ll want to know what’s going wrong or what can be improved. Logging and telemetry can help!</p></li> </ol> <h2> <strong>Wrapping Up Try Catch in CSharp</strong> </h2> <p>Now you’ve had a chance to see the basics of try catch in C#! I’ve aimed to help familiarize you with the purpose of the different blocks, and introduced the finally block as well! With some basic code examples to refer to along with some extra considerations to keep in mind when programming, you’re all set to start catching exceptions in your code!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> csharp dotnet beginners coding How to Convert a String to Byte Array in C#: Encoding and Decoding Simplified Dev Leader Mon, 29 Apr 2024 16:00:00 +0000 https://dev.to/devleader/how-to-convert-a-string-to-byte-array-in-c-encoding-and-decoding-simplified-3faf https://dev.to/devleader/how-to-convert-a-string-to-byte-array-in-c-encoding-and-decoding-simplified-3faf <p>In programming, it’s very common that we need to go between strings and bytes. Humans read strings. Computers read bytes. As a result, it’s important for us dotnet developers to understand how to convert a string to a byte array in C#. We accomplish this through a process called encoding and decoding to go back and forth between the two.</p> <p>In this article, I’ll provide you code examples to be able to convert a string to a byte array in C# — and back again! You’ll also learn about some of the nuances of character encodings to look out for!</p> <h2> <strong>Encoding and Decoding in CSharp</strong> </h2> <p>If we want to convert a string to a byte array — or go the other way — we need to understand the concept of encoding and decoding. In software engineering, encoding refers to the process of transforming a string into a sequence of bytes, while decoding involves the reverse process of transforming bytes back into a string. Simple, right?</p> <p>Remember that strings are a sequence of characters, and the concept of a character makes a lot of sense to us as readers, but computers understand bytes. Characters themselves can be represented by numbers in computers so when we want to work with strings at a lower level, such as when sending data over a network or storing it in a file, we need to convert the string into a byte array.</p> <p>Encoding comes into play when converting strings to byte arrays. It determines <strong>how</strong> the characters in the string are represented as bytes. The <a href="proxy.php?url=https://www.devleader.ca/2023/09/19/ascii-vs-utf8-how-to-navigate-character-encoding/" rel="noopener noreferrer">encoding scheme defines the mapping between characters</a> and their byte representations. <a href="proxy.php?url=https://www.devleader.ca/2023/09/19/ascii-vs-utf8-how-to-navigate-character-encoding/" rel="noopener noreferrer">Common encoding schemes include UTF-8, UTF-16, ASCII, and Unicode</a>.</p> <p>Choosing the correct encoding is important because different encoding schemes support different sets of characters. For example, ASCII only supports the basic English alphabet (with a few more characters), while UTF-8 and UTF-16 are capable of representing characters from multiple languages and scripts. More on this later though since I know you’re eager for some code!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Choosing an Encoding for String to Byte Array Conversion</strong> </h2> <p>When converting strings to byte arrays in C#, one of the most important things to consider is character encoding. Character encoding determines the mapping between characters and byte values, and if you’re considering transforming data one way then you may want to put some thought into how to transform it back!</p> <p>What’s that supposed to mean? Well, if we use a data transform — let’s say taking a string and transforming it to bytes with an ASCII encoding — if there is not a mapping of a particular character to a byte representation we lose that data in the result. Now what happens if you want to go the other way and get your byte array back to a string?</p> <p>Data is missing!</p> <p>In C#, there are various encodings available, including ASCII, UTF-8, and UTF-16, each with its specific characteristics and usage scenarios. Let’s explore these encodings and see how they can be used for string to byte array conversion.</p> <h3> <strong>ASCII Encoding</strong> </h3> <p>ASCII encoding represents characters using 7 bits, allowing for a total of 128 different characters. It’s primarily suitable for handling basic English <a href="proxy.php?url=https://www.devleader.ca/2023/09/19/ascii-vs-utf8-how-to-navigate-character-encoding/" rel="noopener noreferrer">characters and is more space-efficient compared to other encodings</a>. Here’s an example of converting a string to a byte array using ASCII encoding:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">string</span> <span class="n">text</span> <span class="p">=</span> <span class="s">"Hello, World!"</span><span class="p">;</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">asciiBytes</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">ASCII</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">text</span><span class="p">);</span> </code></pre> </div> <p>In many modern applications, ASCII may not be what you’re after. This is especially true if you have users across the globe in locales that are not English. That’s not to say that ASCII <em>cannot</em> be used, but you’ll want to be careful about what data you ASCII encode so as to not lose information during the encoding transform.</p> <p>So keep in mind that the ASCII <a href="proxy.php?url=https://www.devleader.ca/2023/09/19/ascii-vs-utf8-how-to-navigate-character-encoding/" rel="noopener noreferrer">character set represents characters using a 7-bit encoding</a> scheme, allowing for a total of 128 unique characters. However, with the growing need for internationalization and multilingual support, ASCII alone is insufficient to represent all characters effectively.</p> <p>Good thing we have some other options coming right up!</p> <h3> <strong>UTF-8 Encoding</strong> </h3> <p>UTF-8 encoding is a variable-length encoding scheme that can represent any Unicode character. It’s widely used for encoding text in various languages and is backward compatible with ASCII. It uses fewer bytes for representing ASCII characters but may require more bytes for non-ASCII characters. Here’s an example of converting a string to a byte array using UTF-8 encoding:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">string</span> <span class="n">text</span> <span class="p">=</span> <span class="s">"Привет, мир!"</span><span class="p">;</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">utf8Bytes</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">text</span><span class="p">);</span> </code></pre> </div> <h3> <strong>UTF-16 Encoding</strong> </h3> <p>UTF-16 encoding represents characters using either 2 or 4 bytes, making it capable of representing any Unicode character. It’s commonly used by applications that need to handle multilingual text or when interoperability with other systems is required. The encoding can be little-endian or big-endian, with the former being more prevalent. Here’s an example of converting a string to a byte array using UTF-16 encoding:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="kt">string</span> <span class="n">text</span> <span class="p">=</span> <span class="s">"こんにちは、世界!"</span><span class="p">;</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">utf16Bytes</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">Unicode</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">text</span><span class="p">);</span> </code></pre> </div> <h2> <strong>UTF-8 Encoding vs UTF-16 Encoding – What’s The Difference?</strong> </h2> <p>Each of these encodings is variable width, and their size gives them different characteristics when we consider different alphabets.</p> <p>Starting with UTF-8, it’s variable-width and backward-compatible with ASCII. In this encoding:</p> <ul> <li><p>ASCII characters, which are on the range U+0000 to U+007F, take only 1 byte.</p></li> <li><p>In the next range, code points U+0080 to U+07FF take twice as much space at 2 bytes each.</p></li> <li><p>Code points U+0800 to U+FFFF take one more byte, bringing us up to 3 bytes</p></li> <li><p>And finally, code points U+10000 to U+10FFFF take 4 bytes.</p></li> </ul> <p>This can be very effective for English text because those characters will take up minimal space. However, when it comes to Asian text it’s not ideal for the exact opposite reason.</p> <p>Because UTF-16 has code points from U+0000 to U+FFFF take 2 bytes and code points U+10000 to U+10FFFF are double that at 4 bytes, it’s not-so-great for English. It <em>does</em> happen to be better suited for Asian characters though.</p> <p>There’s even UTF-32 encoding! This is a fixed-width encoding where all of the code points take four bytes — unlike the others I’ve mentioned which are dynamic in size. This can use much more storage than the other encodings, but because of its simplicity can be much faster to operate on.</p> <p>Give some consideration to the alphabets you’ll need to support primarily!</p> <h2> <strong>Best Practices for String to Byte Array Conversion</strong> </h2> <p>When converting strings to byte arrays in C#, it’s important to follow best practices to ensure efficiency and reliability. In this section, I’ll discuss some key best practices that you should keep in mind when performing string to byte array conversions.</p> <h3> <strong>Error Handling and Validation</strong> </h3> <p>When working with encodings, it’s important to handle potential errors and validate your data to prevent unexpected behavior in your code. Ideally, you structure the flow of your application such that you know what kind of data you’re dealing with. If you can write code to avoid errors in the first place, this is preferred!</p> <p>We don’t want to have to rely on this but sometimes it’s outside of our control — handling errors is by using try-catch blocks. By encapsulating the conversion code within a try block, you can catch any exceptions that may occur during the conversion process and handle them gracefully. If you don’t have control over the source of the input data, this is something you might need to do for safety.</p> <h3> <strong>Encoding Selection</strong> </h3> <p>C# provides several encoding options for converting strings to byte arrays, such as UTF-8, UTF-16, ASCII, and more. It’s important to select the appropriate encoding based on the specific requirements of your application. Consider factors such as character sets, compatibility with other systems, and performance implications when choosing the encoding.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="c1">// Example of encoding selection</span> <span class="kt">string</span> <span class="n">inputString</span> <span class="p">=</span> <span class="s">"Hello, World!"</span><span class="p">;</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">encodedBytes</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">inputString</span><span class="p">);</span> </code></pre> </div> <p>Just like we saw in the previous examples, after the Encoding class we get to pick the static property holding the encoding instance. If we need to select one to pass around as a variable and parameter, you can absolutely store it in a dedicated encoding reference:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="n">Encoding</span> <span class="n">selectedEncoding</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">;</span> <span class="nf">SomeMethod</span><span class="p">(</span><span class="s">"Hello World!"</span><span class="p">,</span> <span class="n">selectedEncoding</span><span class="p">);</span> </code></pre> </div> <p>Selecting the wrong encoding can have big consequences for your application! This is especially true if you save data with an encoding that will lose data resolution and you can’t reverse it… so put some care into this!</p> <h2> <strong>Now You Know How to Convert a String to Byte Array in CSharp!</strong> </h2> <p>You’re a pro now with encoding and decoding! Well, maybe not a full-on expert… but you have the basics put in front of you and some guidelines to work with. That’s a pretty good start.</p> <p>Remember to select the right encoding for the situation you’re dealing with. Keep in mind that you can potentially lose data resolution when using the wrong encoding, and as a result, lose data forever!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> dotnet csharp beginners programming API Gateways in Zuplo – Creating an ASCII Art API Dev Leader Wed, 24 Apr 2024 16:00:00 +0000 https://dev.to/devleader/api-gateways-in-zuplo-creating-an-ascii-art-api-4gle https://dev.to/devleader/api-gateways-in-zuplo-creating-an-ascii-art-api-4gle <p>I was approached by Adrian Machado, an employee at <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>, for a problem I didn’t even know I had — yet. When I jumped on the call with him to walk through their product offering, I remember thinking “Holy crap — this is for me”. You see, I’m more than happy to code up solutions for things and build systems, but there’s a class of work that I REALLY don’t want to have to deal with. And every single time I work on a new project/product/service that’s web-facing this stuff comes up every time… And API Gateways in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> I feel like make this infinitely more easy to navigate.</p> <p>In this article, I’m going to share with you my experiences with onboarding <a href="proxy.php?url=https://www.devleader.ca/2023/08/25/generate-ascii-art-a-simple-how-to-in-c/" rel="noopener noreferrer">my ASCII art generator</a> onto an API Gateway in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>. To cover all of the capabilities, I’ll need to spread this out over several articles, but this will explain how I achieved routing traffic through the gateway!</p> <p><strong><em>Full disclosure</em></strong>: <a href="proxy.php?url=https://www.devleader.ca/2024/04/19/api-gateways-in-zuplo-creating-an-ascii-art-api/" rel="noopener noreferrer">Zuplo sponsored the article for my website</a>, but I wanted to share it on additional platforms because I genuinely enjoyed working with it.</p> <h2> <strong>What is Zuplo?</strong> </h2> <p><a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> is an API Management platform that places an emphasis on the Developer Experience (DevEx) for building web APIs. <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>‘s goal is to build a platform to make it fast and straightforward to build awesome APIs. Directly from them:</p> <blockquote> <p><em>We are trying to build a platform to make it fast and straightforward for developers to deliver a Stripe-level API experience to their users.</em></p> <p><a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer"><em><cite>Zuplo</cite></em></a></p> </blockquote> <p>It’s one thing to get the logic for an API implemented — which is where historically I shine pretty well. But building out a fully operational API that you can have users and other services relying on isn’t a trivial process — especially once you consider monetizing it. You’ll need to factor in:</p> <ul> <li><p>Documentation</p></li> <li><p>Testing</p></li> <li><p>Deployments</p></li> <li><p>Monitoring</p></li> </ul> <p>Nevermind all of the other things regarding access and protection like authentication and rate limiting… The list goes on. But <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> aims to try and get you focused on what matters (what your API needs to do) so they can handle the rest.</p> <h3> <strong>What is an API Gateway?</strong> </h3> <p>An API Gateway is a component in many modern distributed systems, particularly — but not exclusively — in microservices architectures. It acts like the bouncer at the club of your backend services, managing and directing incoming API calls from clients to various backend services. I like to think of it like “the front door” — although it does more than that.</p> <p>So… What exactly does that mean?</p> <p>When you have a bunch of services, each handling a specific piece of functionality (like billing, user profiles, inventory, etc.), it’s not always ideal to have everyone on the outside of your system hitting them directly. And now you might ask, “Well… Why?”, and that’s because managing all those direct connections can get messy.</p> <p>Think about handling authentication, rate limiting, and data transformation for each service individually. That’s where the API Gateway comes into play. These can simplify a lot of the interactions between services as well as callers to your services on the outside. The API Gateway simplifies client interactions with your service or services — like my front door analogy — providing a single entry point for all client requests.</p> <h3> <strong>What Does Zuplo Offer for API Gateways?</strong> </h3> <p>While this article will not be covering all of these in detail (c’mon, I need to spread out the juicy details a little bit…), here are some of the core offerings from <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> with respect to API gateways:</p> <ul> <li><p><a href="proxy.php?url=https://zuplo.com/features/api-key-management" rel="noopener noreferrer">API Key Management</a>: Zuplo allows you to add API key-based authentication to your APIs rapidly — literally in a few minutes.</p></li> <li><p><a href="proxy.php?url=https://zuplo.com/features/rate-limiting" rel="noopener noreferrer">Rate Limiting and Throttling</a>: Zuplo’s rate-limiting functionality can work great when paired with their other features, like the API keys I just mentioned. They have ready-to-go limiting based on keys or JWTs but they also allow you to customize this further in code.</p></li> <li><p><a href="proxy.php?url=https://zuplo.com/docs/handlers/url-forward" rel="noopener noreferrer">Routing and Forwarding</a>: With <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>, you can handle the request right at the edge server using the code you write in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> itself, you can run a lambda, or you can forward/rewrite the request!</p></li> </ul> <p>Yes, sure, these are all things that <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> didn’t invent, but using these within <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> means you don’t have to go build them from scratch — and they make it ridiculously easy for you to use.</p> <p>But what else does their platform do for you if you’re developing APIs?</p> <ul> <li><p><a href="proxy.php?url=https://zuplo.com/docs/policies" rel="noopener noreferrer">Full Policy Library</a>: It’s actually almost ridiculous how many out-of-the-box policies are provided for what you might want to do with your API. Think of these almost like a “middleware” that you can insert inbound and outbound on your API as building blocks — which means you don’t need to go build this stuff from scratch!</p></li> <li><p><a href="proxy.php?url=https://zuplo.com/docs/articles/dev-portal-configuration" rel="noopener noreferrer">Documentation Generation</a>: Right in the portal you’re able to configure and define documentation for your APIs, but all of the heavy lifting is done for you. Simply make your changes, customize what you want in your documentation, save and it’s automatically deployed to an easily consumable API documentation portal.</p></li> <li><p><a href="proxy.php?url=https://zuplo.com/features/unlimited-environments" rel="noopener noreferrer">Automatic Rapid Deployments</a>: During my demo, I was blown away by just making changes in the portal, and pressing save, and everything is instantly deployed and live. Honestly, the API developer experience feels ridiculously smooth for these features because of how simple and quick these things become.</p></li> </ul> <h2> <strong>ASCII Art Generator Via Zuplo</strong> </h2> <p>In the following sections, I’ll walk you through how I went from my desktop C# ASCII art generator to an API endpoint on <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> that hits my server in the cloud! You can also watch <a href="proxy.php?url=https://youtu.be/5zdOvmAMPwk" rel="noopener noreferrer">the companion video where I explain how I got my ASCII art generator API setup with an API gateway</a>:</p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/5zdOvmAMPwk"> </iframe> </p> <h3> <strong>Why an ASCII Art Generator?</strong> </h3> <p>In 2023 I wrote an <a href="proxy.php?url=https://www.devleader.ca/2023/08/25/generate-ascii-art-a-simple-how-to-in-c/" rel="noopener noreferrer">article on ASCII art and how to create an ASCII art generator in C#</a>. I thought this was a fun little project, but it ended up being one of the articles that still — to this very day — drives a lot of traffic to my website. Even <a href="proxy.php?url=https://youtu.be/Mk8bwXIZTXg" rel="noopener noreferrer">the YouTube video</a>, which I’ll embed right after, has a thumbnail that still ranks quite high on Google!</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxb252fz62f7kun0t8ug.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxb252fz62f7kun0t8ug.png" alt="ASCII Art Generator in C# - Thumbnail on Google Images" width="800" height="533"></a></p> <p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/Mk8bwXIZTXg"> </iframe> </p> <p>This <a href="proxy.php?url=https://www.devleader.ca/2023/08/17/building-projects-unlock-success-as-a-beginner-programmer/" rel="noopener noreferrer">project was fun to build</a>, drove traffic to my site, and was quite self-contained with respect to the amount and complexity of code. I figured that this would be a perfect candidate to build an API for.</p> <p>But back when I first started getting traction for this content, I really didn’t want to be bothered with building out all of the rate-limiting, auth, etc… These are all things I know can be done when <a href="proxy.php?url=https://www.devleader.ca/2023/10/15/how-to-build-a-personal-website-in-blazor-an-asp-net-core-tutorial/" rel="noopener noreferrer">building ASP.NET core</a> applications, but honestly, I couldn’t be bothered to invest the time.</p> <p>But <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> changes that for me because the reality is I don’t have to invest much time at all! I mean this candidly: When Adrian from <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>o got on the call with me, I didn’t even realize I had a problem that <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> would solve until he started walking me through their offering. I realized literally while on the call that <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> is what could allow me to skip over the parts of API development that I truly just don’t want to work on!</p> <h3> <strong>Initial Challenges — Nick’s Fault!</strong> </h3> <p>Thanks to the code being very simple for ASCII art generation, I figured I’d just port everything over directly to <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>! One of the very cool features of <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> is that I can define a route’s logic RIGHT in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> using Typescript:</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91nfvgecbh5534w4rsvt.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91nfvgecbh5534w4rsvt.png" alt="Zuplo Route Request Handler" width="800" height="282"></a></p> <p>It’s worth noting that just by doing that configuration, <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> will automatically go add the associated Typescript file for you:</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbmp8kkufmi4h8wkg6ya.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbmp8kkufmi4h8wkg6ya.png" alt="Zuplo Route Request Handler with Typescript Code" width="800" height="421"></a></p> <p>So this is TOTALLY awesome — especially for Typescript folks. But here’s where my challenge started.</p> <p>Because I’m dealing with images, I need a package that handle different image formats. In order to get this set up in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>, which is very doable, I have to understand a little bit more about building things in Typescript. Directly from their documentation:</p> <blockquote> <p><em>Additionally, you can also bundle custom modules inside of your own project. This process is does require some knowledge of node and npm, but it allows you to use any module or version of the module. To learn how to bundle your own modules, see the sample</em> <a href="proxy.php?url=https://github.com/zuplo/zuplo/tree/main/examples/custom-module" rel="noopener noreferrer"><em>Custom Modules on Github</em></a><em>.</em></p> <p><a href="proxy.php?url=https://zuplo.com/docs/articles/node-modules" rel="noopener noreferrer"><em><cite>Zuplo</cite></em></a></p> </blockquote> <p>So for those of you who work with Node and you’re familiar with all of this stuff — Lucky for you, this should be trivial! For me, the easiest thing was to pivot.</p> <p>While it would be super cool to have my API running completely on <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a>‘s edge servers, I already have machines up hosted in the cloud. It was time to turn to Azure!</p> <h3> <strong>Deploying A Web Service to Azure</strong> </h3> <p>Fortunately for me, I already had a multi-purpose API server set up in Azure that I use for several of my other projects. It’s completely plugin-based, so any time I’d like to extend functionality and add new feature sets, I just add new plugins!</p> <p>In this case, it was almost just as simple as copying the example code that I had from my previous article on building an ASCII art <a href="proxy.php?url=https://www.devleader.ca/2023/09/26/blazor-renderfragment-how-to-use-plugins-to-generate-html/" rel="noopener noreferrer">generator in C# over to a new plugin</a> namespace in my existing web app. One of the small steps I needed to take was putting the web API in place for the first time though!</p> <p>This was an interesting opportunity though because I wasn’t writing an API in C# for end-users to hit… I was writing an API for <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> to hit! While I don’t want to write a crappy API right at my origin, I figured that at least <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> would allow me to build transforms to my API if needed.</p> <p>Here’s a quick peek at what my code looks like on the server side:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">using</span> <span class="nn">Autofac</span><span class="p">;</span> <span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span> <span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">AsciiModule</span> <span class="p">:</span> <span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="n">builder</span> <span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">AsciiArtFromUrlRequestValidator</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span> <span class="p">.</span><span class="n">RegisterType</span><span class="p">&lt;</span><span class="n">AsciiArtGenerator</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">AsImplementedInterfaces</span><span class="p">()</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">routeGroup</span> <span class="p">=</span> <span class="n">app</span><span class="p">.</span><span class="nf">MapGroup</span><span class="p">(</span><span class="s">"ascii"</span><span class="p">);</span> <span class="c1">// FIXME: correct the container ordering-issue to inject properly</span> <span class="kt">var</span> <span class="n">imageSourceFactory</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IImageSourceFactory</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">asciiArtGenerator</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IAsciiArtGenerator</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">asciiArtFromUrlRequestValidator</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">AsciiArtFromUrlRequestValidator</span><span class="p">&gt;();</span> <span class="n">routeGroup</span><span class="p">.</span><span class="nf">MapPost</span><span class="p">(</span> <span class="s">"/url"</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span> <span class="p">[</span><span class="n">FromBody</span><span class="p">]</span> <span class="n">AsciiArtFromUrlRequest</span> <span class="n">request</span><span class="p">,</span> <span class="n">IHttpClientFactory</span> <span class="n">httpClientFactory</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(!</span><span class="n">asciiArtFromUrlRequestValidator</span><span class="p">.</span><span class="nf">Validate</span><span class="p">(</span><span class="n">request</span><span class="p">).</span><span class="n">IsValid</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">Results</span><span class="p">.</span><span class="nf">BadRequest</span><span class="p">();</span> <span class="p">}</span> <span class="c1">// FIXME: introduce further validations</span> <span class="n">Stream</span> <span class="n">imageStream</span><span class="p">;</span> <span class="k">try</span> <span class="p">{</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">client</span> <span class="p">=</span> <span class="n">httpClientFactory</span><span class="p">.</span><span class="nf">CreateClient</span><span class="p">();</span> <span class="n">imageStream</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span> <span class="p">.</span><span class="nf">GetStreamAsync</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">ImageUrl</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">)</span> <span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">{</span> <span class="k">return</span> <span class="n">Results</span><span class="p">.</span><span class="nf">Problem</span><span class="p">();</span> <span class="p">}</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">imageSource</span> <span class="p">=</span> <span class="n">imageSourceFactory</span><span class="p">.</span><span class="nf">CreateFromStream</span><span class="p">(</span><span class="n">imageStream</span><span class="p">);</span> <span class="kt">var</span> <span class="n">art</span> <span class="p">=</span> <span class="n">asciiArtGenerator</span><span class="p">.</span><span class="nf">GenerateAsciiArtFromImage</span><span class="p">(</span> <span class="n">imageSource</span><span class="p">,</span> <span class="n">AsciiGenerationOptions</span><span class="p">.</span><span class="n">Default</span> <span class="k">with</span> <span class="p">{</span> <span class="n">ScaleDownFactor</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">ScaleDownFactor</span><span class="p">,</span> <span class="n">HorizontalStretchFactor</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">HorizontalStretchFactor</span> <span class="p">});</span> <span class="n">AsciiArtResponse</span> <span class="n">response</span> <span class="p">=</span> <span class="k">new</span><span class="p">(</span> <span class="n">art</span><span class="p">.</span><span class="n">Art</span><span class="p">,</span> <span class="n">art</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="n">art</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span> <span class="k">return</span> <span class="n">Results</span><span class="p">.</span><span class="nf">Ok</span><span class="p">(</span><span class="n">response</span><span class="p">);</span> <span class="p">});</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">RouteRegistrationDependencyMarker</span><span class="p">();</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>The code above gives us a POST route on the server that’s essentially just &lt;server&gt;/ascii/url, which takes a URL that my server can work with. I’d like to opt for switching over to an API where image bytes can be uploaded, but this seemed like an easy way to get started.</p> <p>This isn’t going to be a full tutorial on deploying to Azure by any means but using “App Service” within Azure, I have full git-actions integration so that every time I make a commit, my application is deployed.</p> <h3> <strong>My Zuplo API is Alive!</strong> </h3> <p>Now that my own server is deployed in Azure, it’s time to rock and roll! This is where the simplicity of <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> really shines. Here’s the new route I added with URL rewriting:</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszt4vmiajyv4girzycdz.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszt4vmiajyv4girzycdz.png" alt="Zuplo ASCII Art Route Forwarding" width="800" height="307"></a></p> <p>I literally only had to press the save button (not shown in the screenshot) and within about 3 seconds the test button became live for me to use. Directly from the browser, much like using Postman, I was able to send a test URL and get back some fancy ASCII art. I’ll skip the screenshot because Zuplo isn’t optimized to try rendering ASCII art for us — I know, I know… a critical flaw!</p> <h2> <strong>Security Between Azure and Zuplo API Gateway</strong> </h2> <p>As I was putting all of this together, I said “Wait a sec! My server is still exposed to the Internet without ANY protection in front of it!”. This is realistically not a <em>huge</em> problem at the moment because nobody even knows the address of it. But still — I wanted to do this properly.</p> <p>I reached out to <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> and asked “Hey, what’s your recommended way to do this?”, just in case they had more magic up their sleeves. They politely explained and mentioned that’s also <a href="proxy.php?url=https://zuplo.com/docs/articles/step-1-setup-basic-gateway" rel="noopener noreferrer">covered in the example getting started documentation</a>. And obviously, I read that ahead of time… we ALWAYS read the docs… right?</p> <p>RIGHT?</p> <p>After reading the documentation, I had one little change to make on my server, which was using a custom <a href="proxy.php?url=https://www.devleader.ca/2024/04/18/api-key-authentication-middleware-in-asp-net-core-a-how-to-guide/" rel="noopener noreferrer">middleware for adding API authentication</a>. By the way, if I haven’t sold you on plugin architecture before, API <a href="proxy.php?url=https://www.devleader.ca/2024/04/18/api-key-authentication-middleware-in-asp-net-core-a-how-to-guide/" rel="noopener noreferrer">key authentication</a> for my server was just another plugin:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">ApiKeyModule</span> <span class="p">:</span> <span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">&gt;();</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ApiKeyConfigKey</span> <span class="p">=</span> <span class="s">"&lt;APP_CONFIG_KEY_HERE&gt;"</span><span class="p">;</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">?&gt;</span> <span class="n">lazyApiKey</span> <span class="p">=</span> <span class="k">new</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">config</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="n">ApiKeyConfigKey</span><span class="p">));</span> <span class="n">app</span><span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="k">async</span> <span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">next</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ApiKeyHeader</span> <span class="p">=</span> <span class="s">"&lt;HEADER_KEY_GOES_HERE&gt;"</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="n">context</span><span class="p">.</span><span class="n">Request</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">ApiKeyHeader</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">apiKeyVal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Api Key not found."</span><span class="p">);</span> <span class="p">}</span> <span class="kt">var</span> <span class="n">apiKey</span> <span class="p">=</span> <span class="n">lazyApiKey</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">apiKey</span><span class="p">,</span> <span class="n">apiKeyVal</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Invalid API Key."</span><span class="p">);</span> <span class="p">}</span> <span class="k">await</span> <span class="nf">next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span> <span class="p">});</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">PostAppRegistrationDependencyMarker</span><span class="p">();</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>Now one more super quick change to <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> to add a policy to add my configured API key that I have on my server, and we’re done:</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziq67w9rp724l8g7ijfv.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziq67w9rp724l8g7ijfv.png" alt="Zuplo Policy Set Headers" width="800" height="597"></a></p> <h2> <strong>What’s Next for API Gateways in Zuplo?</strong> </h2> <p>At this point, I have a public API through <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> that can get hit, uses an API key with my own server, forwards that request, and gets the response. It’s a full end-to-end integration which I <em>would</em> have loved to do right within <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> — but my Typescript skills were mocking me. That will certainly be an exercise for the future because I think it would be awesome to have this one truly at the edge node.</p> <p>But before I can make this API public, I still need a few more things… And I never actually accomplished them yet:</p> <ul> <li><p>API Documentation</p></li> <li><p>Rate limiting</p></li> <li><p>Authentication</p></li> <li><p>Monetization!</p></li> </ul> <p>The good news is that since I have my API integrated with <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> now, a lot of what’s left is almost all drag-and-drop in their portal! I don’t suspect I’ll have to code anything inside of my own server at this point.</p> <h2> <strong>Wrapping Up API Gateways in Zuplo</strong> </h2> <p>Overall, I thought this was an awesome platform to work with. Getting API Gateways in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> setup is simple and quick — it’s hard to argue with those two things. But if you consider people like me who don’t want to go hand-roll this kind of stuff per service they create, the fact that they’ve integrated so many building blocks makes this dreamy. There were policies in the catalog that made me think “Oh crap! I didn’t even consider that!”.</p> <p>I’m looking forward to continuing to build this API out in <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> and getting it to a point where I can monetize it! So keep your eyes peeled — because you’ll soon have an ASCII art API you can integrate with. While yes, this post is sponsored by <a href="proxy.php?url=https://zuplo.link/nick-gateway" rel="noopener noreferrer">Zuplo</a> , I can say without a doubt their platform greatly simplifies a lot of the pain points I never enjoy dealing with when I develop.</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> api webdev programming azure API Key Authentication Middleware In ASP NET Core – A How To Guide Dev Leader Tue, 23 Apr 2024 16:00:00 +0000 https://dev.to/devleader/api-key-authentication-middleware-in-asp-net-core-a-how-to-guide-2ol9 https://dev.to/devleader/api-key-authentication-middleware-in-asp-net-core-a-how-to-guide-2ol9 <p>While putting some special content together, I found myself needing to integrate API key authentication middleware into my ASP.NET Core application. <a href="proxy.php?url=https://www.devleader.ca/2024/01/31/custom-middleware-in-asp-net-core-how-to-harness-the-power/" rel="noopener noreferrer">I’ve written before about using custom middleware in ASP.NET</a>, but I’ve also been trying to do a better job of documenting smaller code changes like this so the next time I’m looking I have an easy reference.</p> <p>And that means YOU get some free code and a reference guide to go along with it!</p> <h2> <strong>What is Middleware in ASP.NET Core?</strong> </h2> <p>Middleware in ASP.NET Core is code that you can add into an application’s pipeline to handle requests and responses. Each of these components can:</p> <ul> <li><p>Choose whether to pass the request to the next component in the pipeline</p></li> <li><p>Can perform work before and after the next component in the pipeline.</p></li> </ul> <p>When building an ASP.NET Core application, middleware can be used to implement functionality such as authentication, error handling, logging, and serving static files. The list goes on, and you can even <a href="proxy.php?url=https://www.devleader.ca/2024/01/31/custom-middleware-in-asp-net-core-how-to-harness-the-power/" rel="noopener noreferrer">implement your own custom middleware</a>. If you’d like more information on middleware to get started, you can check out this article that I’ve written:</p> <ul> <li><a href="proxy.php?url=https://www.devleader.ca/2024/01/31/custom-middleware-in-asp-net-core-how-to-harness-the-power/" rel="noopener noreferrer">Custom Middleware in ASP.NET Core – How to Harness the Power!</a></li> </ul> <p>For our use case here, we’ll be looking at adding our own <a href="proxy.php?url=https://www.devleader.ca/2024/01/31/custom-middleware-in-asp-net-core-how-to-harness-the-power/" rel="noopener noreferrer">custom middleware</a> to an ASP.NET Core application. Given that we want to do some type of authentication with an API key, we should be able to create middleware that STOPS processing if the key is invalid or CONTINUE processing if the key is valid. Should be simple enough, right? Let’s continue on and see!</p> <h2> <strong>API Key Authentication Middleware Example Code</strong> </h2> <p>Now that you understand what middleware in ASP.NET core is, let’s look at an example. For my application, I wanted to handle the API key from the request header. Of course, this could be done in different ways, like having a query parameter for example, but the header was what I decided to go with.</p> <p>Here’s the example API key authentication middleware in this code snippet:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">MyMiddleware</span><span class="p">(</span> <span class="n">HttpContext</span> <span class="n">context</span><span class="p">,</span> <span class="n">RequestDelegate</span> <span class="n">next</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// if you wanted it as a query parameter, you'd</span> <span class="c1">// want to consider changing this part of the code!</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ApiKeyHeader</span> <span class="p">=</span> <span class="s">"&lt;YOUR_HEADER_KEY_HERE&gt;"</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="n">context</span><span class="p">.</span><span class="n">Request</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">ApiKeyHeader</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">apiKeyVal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Api Key not found."</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">const</span> <span class="n">TheRealApiKey</span> <span class="p">=</span> <span class="s">"&lt;YOUR_SECRET_API_KEY_HERE&gt;"</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">TheRealApiKey</span><span class="p">,</span> <span class="n">apiKeyVal</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Invalid API Key."</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">await</span> <span class="nf">next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>The code above is very much representative of <a href="proxy.php?url=https://www.devleader.ca/2024/01/05/chain-of-responsibility-pattern-in-c-simplified-how-to-guide/" rel="noopener noreferrer">the chain of responsibility design pattern</a>! Our middleware handler can take action, and then is able to call into the next delegate using the context that was passed in — or it can terminate the sequence by writing a response back and leaving the method without calling the next handler. But if you’re wondering where we hook this up, then check this code snippet:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="c1">// "app" here is the WebApplication instance after</span> <span class="c1">// being built by the web application builder</span> <span class="n">app</span><span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="n">MyMiddleware</span><span class="p">);</span> </code></pre> </div> <p>Odds are you do NOT want to have your API key right in your code — in fact, I would say “PLEASE DO NOT DO THIS!” so that you don’t accidentally commit a secret API key into your source control. A way that we can work around this is by using environment variables and the app configuration! So in the following code example, you can see a string value being looked up in the application’s configuration:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="c1">// "app" here is the WebApplication instance after</span> <span class="c1">// being built by the web application builder</span> <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">app</span><span class="p">.</span><span class="n">Configuration</span> <span class="kt">var</span> <span class="n">secretApiKey</span> <span class="p">=</span> <span class="n">config</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="s">"&lt;CONFIG_KEY_NAME&gt;"</span><span class="p">);</span> </code></pre> </div> <p>Now instead of comparing against a hard-coded API key directly in your code, you can read it from a configuration instance, which can be populated by environment variables!</p> <h2> <strong>Using This With Plugin Architecture in CSharp</strong> </h2> <p>It’s no secret that <a href="proxy.php?url=https://www.devleader.ca/2024/03/12/plugin-architecture-in-c-for-improved-software-design/" rel="noopener noreferrer">I like using plugin architectures when I’m developing software</a> — but this might be your first time reading some of my content. So spoiler alert: I love using <a href="proxy.php?url=https://www.devleader.ca/2023/09/07/plugin-architecture-design-pattern-a-beginners-guide-to-modularity/" rel="noopener noreferrer">plugins when designing</a> software systems.</p> <p>In the ASP.NET Core application that I wanted to add my API key authentication middleware to, I have a very simple loading scheme that allows dependencies to “hook” into the web application building process. This is accomplished by a couple of basic steps:</p> <ul> <li><p>I use Autofac and assembly scanning to look for DLLs with Autofac modules to load in at startup time</p></li> <li><p>These DLLs become plugins, so by definition any plugin can then use the dependency container builder to register their own dependencies</p></li> <li><p>Part of that registration process means they can ask the container for the web application instance that was built</p></li> <li><p>Once they have that web application instance, they are able to hook up their middleware to it.</p></li> </ul> <p>This is a very simple/naive way to do this because there’s no ordering or control on the middleware. If certain middleware MUST be registered before/after other middleware, there’s no opportunity to say so — You just buckle up and hope for the best. However, that’s okay for now because my middleware needs are EXTREMELY limited currently. I will create an ordering scheme for this if/when necessary.</p> <p>So what does my plugin code look like? Pretty much what we saw earlier, except <a href="proxy.php?url=https://www.devleader.ca/2023/10/02/how-to-organize-autofac-modules-5-tips-for-organizing-code/" rel="noopener noreferrer">inside of an Autofac module</a>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight csharp"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">ApiKeyModule</span> <span class="p">:</span> <span class="n">Module</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Load</span><span class="p">(</span><span class="n">ContainerBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">WebApplication</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">ctx</span><span class="p">.</span><span class="n">Resolve</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">&gt;();</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ApiKeyConfigKey</span> <span class="p">=</span> <span class="s">"API_CONFIG_KEY_NAME"</span><span class="p">;</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">?&gt;</span> <span class="n">lazyApiKey</span> <span class="p">=</span> <span class="k">new</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">config</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="n">ApiKeyConfigKey</span><span class="p">));</span> <span class="n">app</span><span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="k">async</span> <span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">next</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ApiKeyHeader</span> <span class="p">=</span> <span class="s">"HEADER_KEY_NAME"</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="n">context</span><span class="p">.</span><span class="n">Request</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span> <span class="n">ApiKeyHeader</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">apiKeyVal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Api Key not found."</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">var</span> <span class="n">apiKey</span> <span class="p">=</span> <span class="n">lazyApiKey</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span> <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">apiKey</span><span class="p">,</span> <span class="n">apiKeyVal</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="m">401</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Invalid API Key."</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">await</span> <span class="nf">next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span> <span class="p">});</span> <span class="c1">// this is used to help control the ordering of dependencies</span> <span class="c1">// so the application won't start until all of these</span> <span class="c1">// have been resolved!</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">PostAppRegistrationDependencyMarker</span><span class="p">();</span> <span class="p">})</span> <span class="p">.</span><span class="nf">SingleInstance</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>If you’re wondering what the benefit is: I never had to touch any other code in my project and I instantly added API authentication to every single route. This code <em>is</em> currently in the main assembly, but I could have added it to a new project, built the DLL, and dropped it into the running directory to get this behavior activated.</p> <p>That’s the power of building with plugins!</p> <h2> <strong>Wrapping Up API Key Authentication Middleware</strong> </h2> <p>Overall, adding API key authentication middleware in ASP.NET Core applications is quite simple! The middleware can be added directly onto the application instance and you can decide how you’d like to load your secret API key to compare against. By sprinkling in a little bit of C# <a href="proxy.php?url=https://www.devleader.ca/2023/09/07/plugin-architecture-design-pattern-a-beginners-guide-to-modularity/" rel="noopener noreferrer">plugin architecture</a> like I prefer to use in many of my projects, it’s a breeze to extend the functionality of your ASP.NET Core app!</p> <p>If you found this useful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="color-secondary fs-s flex items-center"> <img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zfLf%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F4a947694-4ddd-4cc0-befa-83c12c83141d%252Ffavicon.ico" width="64" height="64"> weekly.devleader.ca </div> </div> </div> </div> <h2> <strong>Want More Dev Leader Content?</strong> </h2> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> webdev api dotnet tutorial 8 Things I Wish I Understood Earlier In My Career Dev Leader Mon, 22 Apr 2024 16:00:00 +0000 https://dev.to/devleader/8-things-i-wish-i-understood-earlier-in-my-career-3eil https://dev.to/devleader/8-things-i-wish-i-understood-earlier-in-my-career-3eil <p>Our lives and careers are journeys, so we should expect that we’ll be learning for the duration we’re on this planet. As long as we’re moving forward in life, we have experiences to learn from. When I reflect on my career, there are a lot of lessons that I wish I could have taught myself early on. While I can’t talk to my younger self, I can share these with you!</p> <p>If you enjoy this kind of content, I often write about it in my weekly newsletter. You can subscribe to it for free:</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> &lt;div class="color-secondary fs-s flex items-center"&gt; &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://substackcdn.com/image/fetch/$s_!zfLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a947694-4ddd-4cc0-befa-83c12c83141d%2Ffavicon.ico" loading="lazy" /&gt; weekly.devleader.ca &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> </div> </div> <br> <h2> <strong>1 – Keep Building</strong> </h2> <p>Keep building things. It doesn’t matter if they’re not million-dollar product ideas. Build things to learn about how they work.</p> <p>The goal when we’re building things, especially early in our software engineering journeys, is not to get-rich-quick. The goal is to practice and learn.</p> <p>There’s no shortcut to mastery except for understanding sooner that there’s no shortcut. We need to <a href="proxy.php?url=https://www.devleader.ca/2023/11/13/how-to-build-an-asp-net-core-web-api-a-practical-beginners-tutorial/" rel="noopener noreferrer">practice — so build</a> software.</p> <h2> <strong>2 – Reinvent The Wheel</strong> </h2> <p>We’re always told to not reinvent the wheel. There’s no point doing it if someone else has already done it.</p> <p>But this isn’t always good advice.</p> <p>Reinventing the wheel is one of the best ways to <a href="proxy.php?url=https://www.devleader.ca/2023/12/29/how-to-understand-a-new-codebase-tips-and-tricks-for-tackling-complex-code/" rel="noopener noreferrer">understand how something works and the complexity</a> behind it. It might not be the best thing to chase in a production environment with paying customers, but it’s great for learning.</p> <p>If you’re ever curious about how things work or interested in the complexities of a system or technology — try building it yourself. You’re almost guaranteed to learn something about what you’re diving into. I’d be shocked if you didn’t!</p> <h2> <strong>3 – Learn In Public</strong> </h2> <p>Document your journey so others can learn alongside you. This can help reinforce learning in so many ways because you need to find ways to explain the concepts that you think you’re now understanding.</p> <p>However, don’t masquerade as an expert. Be humble and acknowledge that you’re new and learning. Others will be more willing to help.</p> <p>Remember that everyone has different opinions. Some people are more loud but it doesn’t make them more correct. In fact, the louder people unwilling to listen to other perspectives are more often than not going to be less helpful. So don’t be discouraged.</p> <p>If people correct your mistakes, this is a great chance for you to take lessons learned and improve!</p> <h2> <strong>4 – We Build Software In Teams</strong> </h2> <p>In the large majority of cases, software is built in teams. This means that you need to focus on communication skills, collaboration skills, and ALL of the other skills that aren’t just technical.</p> <p>When it comes to technical direction, you need to consider that it’s not just your choices.</p> <p>This is a good thing — because the different backgrounds, experiences, and perspectives will allow you to build better software as a group.</p> <h2> <strong>5 – Composition &gt; Inheritance</strong> </h2> <p>Inheritance gets pushed a LOT when teaching programming but if you gravitate towards using composition early then you’ll “shortcut” a few years of really crappy code.</p> <p>Seriously. I’m guilty of writing mountains of code with ridiculously long inheritance hierarchies. I can’t blame this entirely on WinForms and the Controls paradigm that was used… I should have taken some responsibility!</p> <p>I’d spend a good portion of my early career rewriting a lot of overly complex inheritance code because it became too complex.</p> <h2> <strong>6 – Don’t Fear Learning</strong> </h2> <p>Don’t be afraid to learn new things. Building expertise can feel great, but don’t let it make you feel so safe that new things feel scary.</p> <p>You’re going to suck at new things but it’s very temporary. You’ll prove to yourself repeatedly that you eventually get working knowledge and feel very comfortable.</p> <p>In my career, my best growth opportunities were when I was forced into something new and uncomfortable. Every time I came out on top.</p> <p>Discomfort led to incredible learning experiences.</p> <h2> <strong>7 – Own Your Career Development</strong> </h2> <p>Nobody is as interested in your <a href="proxy.php?url=https://www.devleader.ca/2024/01/06/take-control-of-career-progression-dev-leader-weekly-25/" rel="noopener noreferrer">career progression</a> as you are. Great managers will indeed help encourage you and give you opportunities to move things along.</p> <p>But we can’t just sit back and wait for this. We won’t always have amazing managers.</p> <p>The sooner you realize that being passive is not a good strategy for progression, the sooner you can take action.</p> <h2> <strong>8 – Remember To Have Fun</strong> </h2> <p>You’re in this for the long haul, spending many hours of your life building software. You better enjoy it.</p> <p>Not every day is going to be easy. Not every day will be interesting. Not every day will exciting.</p> <p>But overall, you need to find ways to enjoy what you’re doing. It will help you learn. It will help you be engaged. It will help you be motivated to push through interesting challenges.</p> <p>Software engineering is very mentally demanding and it’s often hard to find a good work-life balance… So keep this one in mind throughout your career.</p> <p>What would you add or change? If you found this insightful and you’re looking for more learning opportunities, consider <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer">subscribing to my free weekly software engineering newsletter</a> and check out my <a href="proxy.php?url=https://www.youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer">free videos on YouTube</a>! Meet other like-minded software engineers and <a href="proxy.php?url=https://www.devleader.ca/discord-community-access/" rel="noopener noreferrer">join my Discord community</a>!</p> <div class="crayons-card c-embed text-styles text-styles--secondary"> <div class="c-embed__content"> <div class="c-embed__cover"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" class="c-link align-middle" rel="noopener noreferrer"> <img alt="" src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21zsAG%21%2Cf_auto%2Cq_auto%3Abest%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fdevleaderweekly.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1392344488%2526version%253D9" height="480" class="m-0" width="920"> </a> </div> <div class="c-embed__body"> <h2 class="fs-xl lh-tight"> <a href="proxy.php?url=https://weekly.devleader.ca/embed" rel="noopener noreferrer" class="c-link"> Dev Leader Weekly | Substack </a> </h2> <p class="truncate-at-3"> My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers. </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> &lt;div class="color-secondary fs-s flex items-center"&gt; &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="proxy.php?url=https://substackcdn.com/image/fetch/$s_!zfLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a947694-4ddd-4cc0-befa-83c12c83141d%2Ffavicon.ico" loading="lazy" /&gt; weekly.devleader.ca &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> </div> </div> <br> <h1> <strong>Want More Dev Leader Content?</strong> </h1> <ul> <li>Follow along on this platform if you haven’t already! </li> <li>Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: <a href="proxy.php?url=https://subscribe.devleader.ca/" rel="noopener noreferrer"><strong>SUBSCRIBE FOR FREE</strong></a> </li> <li>Looking for courses? Check out my offerings: <a href="proxy.php?url=https://devleader.ca/courses" rel="noopener noreferrer"><strong>VIEW COURSES</strong></a> </li> <li>E-Books &amp; other resources: <a href="proxy.php?url=https://products.devleader.ca/" rel="noopener noreferrer"><strong>VIEW RESOURCES</strong></a> </li> <li>Watch hundreds of full-length videos on my YouTube channel: <a href="proxy.php?url=https://youtube.com/@devleader?sub_confirmation=1" rel="noopener noreferrer"><strong>VISIT CHANNEL</strong></a> </li> <li>Visit my website for hundreds of articles on various software engineering topics (including code snippets): <a href="proxy.php?url=https://devleader.ca/" rel="noopener noreferrer"><strong>VISIT WEBSITE</strong></a> </li> <li>Check out the repository with many code examples from my articles and videos on GitHub: <a href="proxy.php?url=https://github.com/ncosentino/DevLeader" rel="noopener noreferrer"><strong>VIEW REPOSITORY</strong></a> </li> </ul> </div> </div> </div> </div> career learning codenewbie writing The Impact of Lazy Evaluation of Iterators Dev Leader Sun, 21 Apr 2024 06:59:22 +0000 https://dev.to/devleader/the-impact-of-lazy-evaluation-of-iterators-dl2 https://dev.to/devleader/the-impact-of-lazy-evaluation-of-iterators-dl2 <p>Hey friends! <a href="proxy.php?url=https://youtube.com/@devleader" rel="noopener noreferrer">I post TONS of videos on YouTube</a>... Do you want me to cross-post my videos here to Dev.to?!</p>