<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title><![CDATA[  ]]></title>
<description><![CDATA[  ]]></description>
<link></link>
<image>
    <url>/favicon.png</url>
    <title></title>
    <link></link>
</image>
<lastBuildDate>Tue, 10 Mar 2026 12:39:52 -0500</lastBuildDate>
<atom:link href="" rel="self" type="application/rss+xml"/>
<ttl>60</ttl>

    <item>
        <title><![CDATA[ Write cleaner code with C# 14&#x27;s null-conditional assignment operator ]]></title>
        <description><![CDATA[ ℹ️This post was originally published on the Telerik Developer Blog.

When looking at the C# 14 updates coming out soon, I discovered a feature and thought, &quot;how did this not already exist?&quot; If you&#39;ve been using C#&#39;s null-conditional operators (?. and ?[]) for years like ]]></description>
        <link>https://www.daveabrock.com/2025/12/14/write-cleaner-code-with-c-14s-null-conditional-assignment-operator/</link>
        <guid isPermaLink="false">69076f0a1eb2e80001bf164f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 13 Dec 2025 18:46:14 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1499750310107-5fef28a66643?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDJ8fGFzc2lnbm1lbnR8ZW58MHx8fHwxNzYyMDk2MjU2fDA&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">ℹ️</div><div class="kg-callout-text">This post was originally published on the <a href="https://www.telerik.com/blogs/write-cleaner-code-csharp-14-null-conditional-assignment-operator?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</div></div><p>When looking at the <a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14?ref=daveabrock.com" rel="noreferrer">C# 14 updates coming out soon</a>, I discovered a feature and thought, "how did this not already exist?" If you've been using C#'s null-conditional operators (<code>?.</code> and <code>?[]</code>) for years like I have, you'll love the support for <a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14?ref=daveabrock.com#null-conditional-assignment" rel="noreferrer">null-conditional assignments</a>.</p><h2 id="our-long-null-journey">Our long null journey </h2><p>It's been a long journey to improve how C# developers work with <code>null</code>, <a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/?ref=daveabrock.com" rel="noreferrer">the billion-dollar mistake</a>.</p><p>C# 2 kicked things off with nullable value types (like <code>int?</code> and <code>bool?</code>) because sometimes you need to know if someone didn't enter a number versus entering zero. With C# 6, we got null-conditional operators (<code>?.</code> and <code>?[]</code>), letting us chain through potentially null objects without writing novels. C# 7 gave us pattern matching with <code>is null</code> checks that read like English. C# 8 came out with nullable reference types, the null-coalescing operator (<code>??=</code>), and the null-forgiving operator (<code>!</code>) for when you think you know better than the compiler. And, of course, C# 9 rounded it out with <code>is not null</code> because <code>is null</code> was feeling lonely.</p><p>For me, the null-conditional operators from C# 6 were a game-changer. Instead of doom-checking each level of potential nulls, I can just chain it.</p><pre><code class="language-csharp">// The old way
string? city = null;
if (customer != null &amp;&amp; customer.Address != null)
{
    city = customer.Address.City;
}

// The new way
string? city = customer?.Address?.City;</code></pre><p>This was great for reading values. However, we could never use the same trick for <em>writing</em> values. Enter C# 14.</p><h2 id="the-current-problem">The current problem</h2><p>How many times have you written code like this?</p><pre><code class="language-csharp">if (customer != null)
  customer.Order = GetOrder(customer.Id)</code></pre><p>If you're anything like me (lucky you), this pattern is burned into your memory. I type it without thinking. But we already have a perfectly good "do this thing if not null" operator. We just couldn't use it for assignments. Weird, yes? We could read through each null conditionally but not write through it. Every little assignment needed its own little null check guard.</p><h2 id="the-c-14-solution">The C# 14 solution</h2><p>C# 14 lets you write this instead:</p><pre><code class="language-csharp">customer?.Order = GetOrder(customer.Id);</code></pre><p>That's it! Clean, readable, and the intent is obvious: "If the customer isn't null, assign the current order to it."</p><p>The semantics are exactly what you'd hope for: the right-hand side (<code>GetOrder(id)</code>) only runs if the left-hand side isn't null. If <code>customer</code> is null, nothing happens — no assignment, no method call, and no exceptions.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">⚠️</div><div class="kg-callout-text">Like any language feature, this is a tool and not a hammer for every nail. There are times when explicit null checks are actually clearer.</div></div><p>For example, don't hide business logic. If null requires specific handling, explicit checks are much clearer.</p><pre><code class="language-csharp">// Less clear - what should happen if account is null?
account?.Balance += deposit;

// Better when null is exceptional
if (account is null)
    throw new InvalidOperationException("Cannot deposit to null account");
    
account.Balance += deposit;</code></pre><p>Watch out for side effects! Remember, the <em>entire</em> right-hand side is skipped if the left is null.</p><pre><code class="language-csharp">// We don't call GetNextId() if the record is null
record?.Id = GetNextId();</code></pre><h2 id="compound-assignments">Compound assignments</h2><p>The real power in this improvement shows up when you use null-conditional assignments with compound assignment operators.</p><pre><code class="language-csharp">// Before C# 14
if (account != null)
{
    account.Balance += deposit;
}

// C# 14
account?.Balance += deposit;</code></pre><p>This works with all compound assignment operators: <code>+=</code>, <code>-=</code>, <code>*=</code>, <code>/=</code>, <code>%=</code>, <code>&amp;=</code>, <code>|=</code>, <code>^=</code>, <code>&lt;&lt;=</code>, <code>&gt;&gt;=</code>, and <code>??=</code>.</p><p>Check out this shopping cart example:</p><pre><code class="language-csharp">public class ShoppingCart
{
    public decimal Subtotal { get; set; }
    public decimal Tax { get; set; }
}

public void ApplyDiscount(ShoppingCart? cart, decimal discountAmount)
{
    // Only apply discount if cart exists
    cart?.Subtotal -= discountAmount;
    
    // Recalculate tax based on new subtotal
    cart?.Tax = cart.Subtotal * 0.08m;
}</code></pre><p>Notice the improvements: no nested ifs, no ceremony, and just the expected "if it's there, update it" logic. Finally.</p><h2 id="when-this-feature-shines">When this feature shines</h2><p>Let's take a look at some brief real-world scenarios where null-conditional assignments are genuinely useful.</p><h3 id="optional-dependencies">Optional dependencies </h3><p>In modern apps, you have services everywhere — like logging, telemetry, caching, and so on — and it seems half of them are optional depending on what features are enabled.</p><pre><code class="language-csharp">public class TelemetryService
{
    private ILogger? _logger;
    private IMetricsCollector? _metrics;
    
    public void RecordEvent(string eventName, Dictionary&lt;string, object&gt; properties)
    {
        // Log only if logger is configured
        _logger?.LogInformation("Event recorded: {EventName}", eventName);
        
        // Track metrics only if collector is available
        _metrics?.EventCount += 1;
    }
}</code></pre><p>With this improvement, our code doesn't get buried under a mountain of <code>if (_logger != null)</code> checks. The dependency is handled right where you use it, which means the happy path (the service is there) stays front and center. This is huge with classes that have multiple optional dependencies. Traditional null checks create a ton of noise that obscures what your code actually does.</p><h3 id="event-handlers-with-optional-subscribers">Event handlers with optional subscribers</h3><p>When you're working with events, subscribers are optional by nature. It's like me watching a football game: sometimes I'm listening and sometimes I'm not. And that's fine.</p><pre><code class="language-csharp">public class ProgressTracker
{
    public IProgress&lt;int&gt;? Progress { get; set; }
    private int _currentStep;
    private int _totalSteps;
    
    public void AdvanceProgress()
    {
        _currentStep++;
        var percentComplete = (_currentStep * 100) / _totalSteps;
        
        // Report only if someone is listening
        Progress?.Report(percentComplete);
    }
}</code></pre><p>With this improvement, publishers don't need to defensively write null checks before every notification. This is great for library code or reusable components where you have zero control over whether consumers attach handlers. Plus, it's self-documenting. <code>Progress?.Report()</code> clearly says "if anyone cares, report progress."</p><h3 id="conditional-updates-with-fluent-apis">Conditional updates with fluent APIs</h3><p>Builder patterns and fluent APIs are obsessed with optional configuration. Sometimes you've set up all the pieces, and sometimes just a few.</p><pre><code class="language-csharp">public class ApplicationBuilder
{
    public DatabaseConfiguration? Database { get; set; }
    public ApiConfiguration? Api { get; set; }
    
    public void ApplyProduction()
    {
        // Safely configure only what exists
        Database?.ConnectionString = Environment.GetEnvironmentVariable("DB_PROD");
        Database?.CommandTimeout += TimeSpan.FromSeconds(30);
        
        Api?.RateLimitPerMinute = 1000;
        Api?.EnableCaching = true;
    }
}</code></pre><p>With this example, configuration methods can be flexible without requiring everything to exist first. This is perfect for plugin architectures or systems where features come and go. You can write configuration code that gracefully handles a mix of initialized components without the spaghetti code.</p><h3 id="collection-operations">Collection operations</h3><p>We consistently work with collections that might not be initialized yet. Think of when you're doing lazy initialization for performance reasons.</p><pre><code class="language-csharp">public class CacheManager
{
    private List&lt;string&gt;? _recentItems;
    private Dictionary&lt;string, object&gt;? _settings;
    
    public void RecordAccess(string item)
    {
        // Add to recent items if cache is initialized
        _recentItems?.Add(item);
        
        // Update access count
        if (_settings?.ContainsKey("accessCount") == true)
        {
            _settings["accessCount"] = ((int)_settings["accessCount"]) + 1;
        }
    }
    
    public void UpdateTheme(string theme)
    {
        // Safe dictionary assignment
        _settings?.["theme"] = theme;
    }
}</code></pre><p>Nice, eh? You can now work with collections that might not exist yet without checking if they exist first. This is great for performance-sensitive code where you want to defer allocating collections until you actually need them ... but you also want clean code. We can now keep the lazy initialization pattern without our code looking like a mess.</p><h2 id="one-gotcha-no-or-%E2%80%93">One gotcha: No ++ or –-</h2><p>Don't kill the messenger: you can't use increment (<code>++</code>) or decrement (<code>--</code>) operators with null-conditional access.</p><pre><code class="language-csharp">// Ope
counter?.Value++;</code></pre><p>If you want this pattern, do the traditional null check or use the compound assignment form.</p><pre><code class="language-csharp">counter?.Value += 1; </code></pre><p>Captain Obvious says: <code>++</code> and <code>--</code> are a read and write operation rolled into one. And that's where semantics can get really weird with null-conditional operators. If <code>counter</code> is <code>null</code>, what should <code>counter?.Value++</code> return? Null? The pre-increment value? The post-increment value that never computed? Instead of confusing everyone, it just isn't supported.</p><h2 id="a-putting-it-all-together-example-a-configuration-system">A "putting it all together" example: a configuration system</h2><p>Let's put this all together with an example. Let's build a super-exciting configuration system that applies environment-specific overrides to application settings.</p><pre><code class="language-csharp">public class AppSettings
{
    public DatabaseConfig? Database { get; set; }
    public ApiConfig? Api { get; set; }
    public LoggingConfig? Logging { get; set; }
    public CacheConfig? Cache { get; set; }
}

public class DatabaseConfig
{
    public string? ConnectionString { get; set; }
    public int CommandTimeout { get; set; }
    public bool EnableRetry { get; set; }
}

public class ApiConfig
{
    public string? Endpoint { get; set; }
    public TimeSpan Timeout { get; set; }
    public int MaxRetries { get; set; }
}

public class ConfigurationUpdater
{
    public void ApplyEnvironmentOverrides(AppSettings? settings, Environment env)
    {
        // Database overrides - only if database config exists
        settings?.Database?.ConnectionString = env.GetVariable("DB_CONNECTION");
        settings?.Database?.CommandTimeout = 60;
        settings?.Database?.EnableRetry = true;
        
        // API configuration - compound assignments work too
        settings?.Api?.Endpoint = env.GetVariable("API_URL");
        settings?.Api?.Timeout += TimeSpan.FromSeconds(30);
        settings?.Api?.MaxRetries = 5;
        
        // Logging adjustments
        settings?.Logging?.Level = LogLevel.Information;
        settings?.Logging?.EnableConsole = env.IsDevelopment();
        
        // Cache settings
        settings?.Cache?.ExpirationMinutes += 15; 
    }
    
    public void ApplyDevelopmentDefaults(AppSettings? settings)
    {
        // Development-specific configuration
        settings?.Database?.EnableRetry = false; // Fail fast in dev
        settings?.Api?.Timeout = TimeSpan.FromSeconds(5); // Shorter timeouts
        settings?.Logging?.Level = LogLevel.Debug;
    }
}</code></pre><p>This allows us to be modular. Not every app needs every config section. A simple POC might only touch database config, while our behemoth needs everything. </p><p>It also allows us to be optional by nature. The settings object itself might be <code>null</code> during early startup and individual sections might not be wired up yet. It be like that sometimes.</p><p>Compare it to the old way. To avert your eyes, I'll use a snippet.</p><pre><code class="language-csharp">// The verbose alternative (please don't do this)
if (settings != null)
{
    if (settings.Database != null)
    {
        settings.Database.ConnectionString = env.GetVariable("DB_CONNECTION");
        settings.Database.CommandTimeout = 60;
    }
    
    if (settings.Api != null)
    {
        settings.Api.Endpoint = env.GetVariable("API_URL");
        settings.Api.Timeout += TimeSpan.FromSeconds(30);
    }
}</code></pre><p>That is a lot of ceremony just for "configure what exists." With null-conditional assignments, we get clean code that focuses on what we're configuring instead of whether we can configure it.</p><h2 id="wrapping-up">Wrapping up</h2><p>Unless you're a language designer, C# 14's null-conditional assignment won't blow your mind. However, it <em>will </em>make your code clearer and easier to write. It takes a pattern we've all typed a thousand times and finally makes it as concise as it should have been all along.</p><p>So next time you catch yourself typing <code>if (x != null) { x.Property = value; }</code>, know there's a better way.</p><p>What patterns will you use with null-conditional assignments? Let me know in the comments, and happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Parsing Santa&#x27;s workshop with strongly typed data (without the coal) ]]></title>
        <description><![CDATA[ This is my post for the 2025 C# Advent. Check out all the great posts!

Every year, Santa&#39;s workshop runs on data: delivery manifests, elf schedules, chimney dimensions, and naughty/nice scores. And like any other legacy system, it&#39;s held together with strings, DateTime comparisons, and ]]></description>
        <link>https://www.daveabrock.com/2025/12/07/parsing-santas-workshop-with-strongly-typed-data-without-the-coal/</link>
        <guid isPermaLink="false">69343e063f75eb00016b1c52</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 07 Dec 2025 09:41:24 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1514192631-251f5f0b14f2?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDExfHxzYW50YXxlbnwwfHx8fDE3NjUwMzE0MzN8MA&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This is my post for the 2025 C# Advent. Check out </em><a href="https://www.csadvent.christmas/?ref=daveabrock.com" rel="noreferrer"><em>all the great posts</em></a><em>!</em></p><p>Every year, Santa's workshop runs on data: delivery manifests, elf schedules, chimney dimensions, and naughty/nice scores. And like any other legacy system, it's held together with strings, <code>DateTime</code> comparisons, and hope.</p><p>In this post, let's modernize Santa's data parsing using modern C# features: </p><ul><li><code>DateOnly</code> / <code>TimeOnly</code></li><li><code>IParsable&lt;TSelf&gt;</code> / <code>ISpanParsable&lt;TSelf&gt;</code></li><li>Strongly typed IDs</li><li>C# 14's new extension members</li></ul><p>The goal here is for more safety, clearer intent, and better performance — all without turning the code into a Christmas puzzle.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">ℹ️</div><div class="kg-callout-text">This post targets .NET 10 / C# 14 for the extension member examples. The other features (<code spellcheck="false" style="white-space: pre-wrap;">DateOnly</code>/<code spellcheck="false" style="white-space: pre-wrap;">TimeOnly</code>, <code spellcheck="false" style="white-space: pre-wrap;">IParsable</code>/<code spellcheck="false" style="white-space: pre-wrap;">ISpanParsable</code>, <code spellcheck="false" style="white-space: pre-wrap;">readonly record struct</code>) are available starting in .NET 6/7.</div></div><h2 id="the-legacy-santa-codebase">The legacy Santa codebase</h2><p>Here's a real "elves stay late" classic: </p><pre><code class="language-csharp">public void AssignGiftToElf(int giftId, int elfId, int workshopId)
{
  Console.WriteLine($"Assigning gift {giftId} to elf {elfId} in workshop {workshopId}");
}

AssignGiftToElf(elfId, giftId, workshopId); </code></pre><p>All of our parameters are <code>int</code> types. The compiler can't help you if you get the order wrong.</p><p>Santa's delivery logic isn't much better (sorry, children, this year not <em>everything </em>is delivered at midnight):</p><pre><code class="language-csharp">public class DeliveryWindow
{
    public DateTime DeliveryDate { get; set; }

    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }

    public bool IsDuringSleepingHours()
    {
        var startHour = StartTime.Hour;
        var endHour = EndTime.Hour;
        
        return startHour &gt;= 22 || endHour &lt;= 6;
    }
}</code></pre><p>We're overusing <code>DateTime</code> for both pure dates and pure times. What time is on <code>DeliveryDate</code>? What date is attached to <code>StartTime</code>? What timezone are these in? You have to know tribal knowledge that isn’t expressed in the type system. </p><p>Let's see how we process our presents.</p><pre><code class="language-csharp">public class DeliveryOrder
{
    public int GiftId { get; set; }
    public int ElfId { get; set; }
    public int WorkshopId { get; set; }
    
    public DateTime DeliveryDate { get; set; }
    public DateTime WindowStart { get; set; }
    public DateTime WindowEnd { get; set; }
    
    public string? ChimneyDimensions { get; set; }
    public string? RecipientName { get; set; }
    public string? Address { get; set; }
}</code></pre><p>The IDs are just <code>int</code> types (easy to mix up), dates and times are all <code>DateTime</code> (potentially confusing), and the <code>ChimneyDimensions</code> is a raw string we'll need to parse manually every time we need it.</p><p>These are potentially critical bugs that'll keep Santa's developers up late. Let's fix them together.</p><h2 id="use-dateonly-and-timeonly-to-say-what-you-mean">Use DateOnly and TimeOnly to say what you mean</h2><p>First thing first: stop using <code>DateTime</code> when you don't actually mean date <em>and</em> time.</p><p>Here's a cleaner <code>DeliveryWindow</code> using <code>DateOnly</code> and <code>TimeOnly</code>:</p><pre><code class="language-csharp">public record DeliveryWindow
{
    public required DateOnly DeliveryDate { get; init; }
    public required TimeOnly WindowStart { get; init; }
    public required TimeOnly WindowEnd { get; init; }

    public bool IsDuringSleepingHours()
    {
        var sleepStart = new TimeOnly(22, 0); // 10 PM
        var sleepEnd = new TimeOnly(6, 0);    // 6 AM

        return WindowStart &gt;= sleepStart || WindowEnd &lt;= sleepEnd;
    }
}
</code></pre><p>Now the type tells you exactly what’s going on:</p><ul><li><code>DeliveryDate</code> is a calendar date, no time, no timezone debates</li><li><code>WindowStart</code> / <code>WindowEnd</code> are times of day</li></ul><p>There's also a performance bonus: <code>DateOnly</code> is half the size of  <code>DateTime</code>.</p><pre><code class="language-csharp">Console.WriteLine(Unsafe.SizeOf&lt;DateTime&gt;());  // 8 bytes
Console.WriteLine(Unsafe.SizeOf&lt;DateOnly&gt;());  // 4 bytes
Console.WriteLine(Unsafe.SizeOf&lt;TimeOnly&gt;());  // 8 bytes</code></pre><p>That may seem like a small difference, but not when you're storing millions of delivery records.</p><p>Starting with EF Core 8, <code>DateOnly</code> and <code>TimeOnly</code> are supported out of the box. <code>DateOnly</code> maps to the SQL <code>date</code> type, and <code>TimeOnly</code> maps to <code>time</code>.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">ℹ️</div><div class="kg-callout-text">If you're on .NET Framework or EF Core 7 or earlier, you'll typically stick with <code spellcheck="false" style="white-space: pre-wrap;">DateTime</code> (or use <code spellcheck="false" style="white-space: pre-wrap;">DateOnly</code>/<code spellcheck="false" style="white-space: pre-wrap;">TimeOnly</code> with value converters). Just make sure to be disciplined about <code spellcheck="false" style="white-space: pre-wrap;">.Date</code> comparisons and document times that are ignored.</div></div><h2 id="use-strongly-typed-ids-for-compile-time-safety">Use strongly typed IDs for compile-time safety</h2><p>Let's fix the "everything is an <code>int</code>" problem.</p><p>Instead of:</p><pre><code class="language-csharp">public void AssignGiftToElf(int giftId, int elfId, int workshopId)
{
    Console.WriteLine($"Assigning gift {giftId} to elf {elfId} in workshop {workshopId}");
}

AssignGiftToElf(elfId, giftId, workshopId); // Compiles, but there be bugs
</code></pre><p>Let's wrap each ID in its own type using <code>readonly record struct</code>:</p><pre><code class="language-csharp">public readonly record struct GiftId(int Value);
public readonly record struct ElfId(int Value);
public readonly record struct WorkshopId(int Value);</code></pre><p>Now our method looks like this:</p><pre><code class="language-csharp">public void AssignGiftToElf(GiftId giftId, ElfId elfId, WorkshopId workshopId)
{
  Console.WriteLine($"Assigning gift {giftId} to elf {elfId} in workshop {workshopId}");
}

AssignGiftToElf(new ElfId(42), new GiftId(17), new WorkshopId(3));</code></pre><p>The call now fails with a helpful error (<code>Cannot convert from 'ElfId' to 'GiftId'</code>) instead of silently mis-routing gifts.</p><p>In terms of runtime overhead, see how the abstraction disappears after we compile:</p><pre><code class="language-csharp">using System;
using System.Runtime.CompilerServices;

Console.WriteLine(Unsafe.SizeOf&lt;int&gt;());
Console.WriteLine(Unsafe.SizeOf&lt;GiftId&gt;());
Console.WriteLine(Unsafe.SizeOf&lt;ElfId&gt;());
Console.WriteLine(Unsafe.SizeOf&lt;WorkshopId&gt;());</code></pre><p>All four of these lines output <code>4</code>, the same size as the underlying <code>int</code>. </p><p>As a bonus, our <code>record struct</code> update gives us value equality for free.</p><pre><code class="language-csharp">var id1 = new GiftId(42);
var id2 = new GiftId(42);
var id3 = new GiftId(43);

Console.WriteLine(id1 == id2); // true
Console.WriteLine(id1 == id3); // false
Console.WriteLine(id1.GetHashCode() == id2.GetHashCode()); // true</code></pre><h2 id="use-iparsabletself-for-generic-parsing">Use IParsable&lt;TSelf&gt; for generic parsing</h2><p>Let's talk about our favorite topic: parsing. </p><p>Our original <code>ChimneyDimensions</code> is pretty ad-hoc:</p><pre><code class="language-csharp">public class ChimneyDimensions
{
    public double WidthInches { get; set; }
    public double HeightInches { get; set; }

    public static ChimneyDimensions Parse(string input)
    {
        var parts = input.Split('x');
        return new ChimneyDimensions
        {
            WidthInches = double.Parse(parts[0]),
            HeightInches = double.Parse(parts[1])
        };
    }

    public bool CanSantaFit() =&gt; WidthInches &gt;= 20 &amp;&amp; HeightInches &gt;= 24;
}</code></pre><p>Sure, this "works." (Imagine my air quotes.) But every type needs its own bespoke <code>Parse</code> method. There's no <code>TryParse</code>, no <code>IFormatProvider</code> for culture handling (important for Santa's global reach!), and we can't write generic code that parses multiple types the same way.</p><p>This is where <code>IParsable&lt;TSelf&gt;</code> comes in handy. While you can always write a <code>Parse</code> method, this makes sure your types easily work with generic utilities, framework features, and other developer code.</p><p>Let's evolve <code>ChimneyDimensions</code> into a modern, value-type version:</p><pre><code class="language-csharp">public readonly record struct ChimneyDimensions : IParsable&lt;ChimneyDimensions&gt;
{
    public double WidthInches  { get; init; }
    public double HeightInches { get; init; }

    public ChimneyDimensions(double width, double height)
        =&gt; (WidthInches, HeightInches) = (width, height);

    public static ChimneyDimensions Parse(string s, IFormatProvider? provider)
    {
        var i = s.IndexOf('x');
        if (i &lt; 0)
            throw new FormatException($"Expected 'WIDTHxHEIGHT', got '{s}'");

        var width  = double.Parse(s[..i],     provider);
        var height = double.Parse(s[(i + 1)..], provider);
        return new(width, height);
    }

    public static bool TryParse(string? s, IFormatProvider? provider,
        out ChimneyDimensions result)
    {
        if (string.IsNullOrEmpty(s))
        {
            result = default;
            return false;
        }

        var i = s.IndexOf('x');
        if (i &lt; 0 ||
            !double.TryParse(s[..i], provider, out var width) ||
            !double.TryParse(s[(i + 1)..], provider, out var height))
        {
            result = default;
            return false;
        }

        result = new(width, height);
        return true;
    }

    public bool CanSantaFit() =&gt; WidthInches &gt;= 20 &amp;&amp; HeightInches &gt;= 24;

    public override string ToString() =&gt; $"{WidthInches}x{HeightInches}";
}
</code></pre><p>Now we can write generic parsing utilities once and reuse everywhere.</p><pre><code class="language-csharp">public static class GenericParser
{
    public static T Parse&lt;T&gt;(string value) where T : IParsable&lt;T&gt;
        =&gt; T.Parse(value, CultureInfo.InvariantCulture);

    public static IEnumerable&lt;T&gt; ParseMany&lt;T&gt;(IEnumerable&lt;string&gt; values)
        where T : IParsable&lt;T&gt;
        =&gt; values.Select(Parse&lt;T&gt;);
}

var giftId  = GenericParser.Parse&lt;GiftId&gt;("12345");
var chimney = GenericParser.Parse&lt;ChimneyDimensions&gt;("24x36");
var date    = GenericParser.Parse&lt;DateOnly&gt;("2024-12-25");
</code></pre><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">ℹ️</div><div class="kg-callout-text">This works for both your custom types and BCL types (<code spellcheck="false" style="white-space: pre-wrap;">int</code>, <code spellcheck="false" style="white-space: pre-wrap;">DateOnly</code>, etc.) as long as they implement <code spellcheck="false" style="white-space: pre-wrap;">IParsable&lt;TSelf&gt;</code>.</div></div><h2 id="use-ispanparsabletself-for-zero-allocation-parsing">Use ISpanParsable&lt;TSelf&gt; for zero-allocation parsing</h2><p><code>IParsable&lt;TSelf&gt;</code> gives us generic parsing, but Santa's Workshop is stressing about performance. We have a 10GB delivery manifest to parse, and those <code>string.Split()</code> allocations add up. GC pressure is killing our throughput.</p><p>Our old way allocated strings for every field.</p><pre><code class="language-csharp">var parts = input.Split('x');  
var width = double.Parse(parts[0]);  
var height = double.Parse(parts[1]);</code></pre><p>The <code>Split</code> call allocates a <code>string[]</code>, and each new element is a new <code>string</code> object. Multiply that by millions of lines and we're on Santa's Naughty List.</p><p><code>ISpanParsable&lt;TSelf&gt;</code> let us parse from <code>ReadOnlySpan&lt;char&gt;</code> (slices of the original string with zero allocations). We can then extend <code>ChimneyDimensions</code>:</p><pre><code class="language-csharp">public readonly record struct ChimneyDimensions :
    IParsable&lt;ChimneyDimensions&gt;, ISpanParsable&lt;ChimneyDimensions&gt;
{
    public double WidthInches  { get; init; }
    public double HeightInches { get; init; }

    public ChimneyDimensions(double width, double height)
        =&gt; (WidthInches, HeightInches) = (width, height);

    // string-based overload delegates to the span-based one
    public static ChimneyDimensions Parse(string s, IFormatProvider? provider)
        =&gt; Parse(s.AsSpan(), provider);

    public static ChimneyDimensions Parse(ReadOnlySpan&lt;char&gt; s, IFormatProvider? provider)
    {
        var i = s.IndexOf('x');
        if (i &lt; 0)
            throw new FormatException("Expected 'WIDTHxHEIGHT'");

        var width  = double.Parse(s[..i],     provider);
        var height = double.Parse(s[(i + 1)..], provider);
        return new(width, height);
    }

    public static bool TryParse(string? s, IFormatProvider? provider,
        out ChimneyDimensions result)
    {
        if (string.IsNullOrEmpty(s))
        {
            result = default;
            return false;
        }

        return TryParse(s.AsSpan(), provider, out result);
    }

    public static bool TryParse(ReadOnlySpan&lt;char&gt; s, IFormatProvider? provider,
        out ChimneyDimensions result)
    {
        var i = s.IndexOf('x');
        if (i &lt; 0 ||
            !double.TryParse(s[..i], provider, out var width) ||
            !double.TryParse(s[(i + 1)..], provider, out var height))
        {
            result = default;
            return false;
        }

        result = new(width, height);
        return true;
    }

    public bool CanSantaFit() =&gt; WidthInches &gt;= 20 &amp;&amp; HeightInches &gt;= 24;

    public override string ToString() =&gt; $"{WidthInches}x{HeightInches}";
}</code></pre><p>Now let’s parse an entire delivery manifest line.</p><p>First, the original approach uses <code>Split</code>, which allocates a <code>string[]</code> with nine elements:</p><pre><code class="language-csharp">public static DeliveryOrder ParseLineOldWay(string line)
{
    var parts = line.Split('|');
    
    return new DeliveryOrder
    {
        GiftId        = new GiftId(int.Parse(parts[0], CultureInfo.InvariantCulture)),  
        AssignedElf   = new ElfId(int.Parse(parts[1], CultureInfo.InvariantCulture)),  
        OriginWorkshop= new WorkshopId(int.Parse(parts[2], CultureInfo.InvariantCulture)), 
        DeliveryDate  = DateOnly.Parse(parts[3], CultureInfo.InvariantCulture),    
        WindowStart   = TimeOnly.Parse(parts[4], CultureInfo.InvariantCulture),    
        WindowEnd     = TimeOnly.Parse(parts[5], CultureInfo.InvariantCulture),    
        Chimney       = ChimneyDimensions.Parse(parts[6], CultureInfo.InvariantCulture),
        RecipientName = parts[7],
        Address       = parts[8]
    };
}
</code></pre><p>Allocations everywhere.</p><p>Our updated version uses a tiny helper:</p><pre><code class="language-csharp">static ReadOnlySpan&lt;char&gt; ReadField(ref ReadOnlySpan&lt;char&gt; line)
{
    var i = line.IndexOf('|');
    if (i &lt; 0)
    {
        var field = line;
        line = ReadOnlySpan&lt;char&gt;.Empty;
        return field;
    }

    var result = line[..i];
    line = line[(i + 1)..];
    return result;
}</code></pre><p>Now parsing the line is concise and allocation-friendly.</p><pre><code class="language-csharp">public static DeliveryOrder ParseLineNewWay(ReadOnlySpan&lt;char&gt; line)
{
    var giftId       = new GiftId(int.Parse(ReadField(ref line), CultureInfo.InvariantCulture));
    var elfId        = new ElfId(int.Parse(ReadField(ref line), CultureInfo.InvariantCulture));
    var workshopId   = new WorkshopId(int.Parse(ReadField(ref line), CultureInfo.InvariantCulture));
    var deliveryDate = DateOnly.Parse(ReadField(ref line), CultureInfo.InvariantCulture);
    var windowStart  = TimeOnly.Parse(ReadField(ref line), CultureInfo.InvariantCulture);
    var windowEnd    = TimeOnly.Parse(ReadField(ref line), CultureInfo.InvariantCulture);
    var chimney      = ChimneyDimensions.Parse(ReadField(ref line), CultureInfo.InvariantCulture);
    var recipient    = ReadField(ref line).ToString();
    var address      = ReadField(ref line).ToString();

    return new DeliveryOrder
    {
        GiftId        = giftId,
        AssignedElf   = elfId,
        OriginWorkshop= workshopId,
        DeliveryDate  = deliveryDate,
        WindowStart   = windowStart,
        WindowEnd     = windowEnd,
        Chimney       = chimney,
        RecipientName = recipient,
        Address       = address
    };
}</code></pre><p>We still allocate strings for <code>RecipientName</code> and <code>Address</code> because we need to store them in the resulting object; everything else is parsed directly from span slices.</p><h2 id="use-c-14-extension-members-to-extend-everything">Use C# 14 extension members to extend everything</h2><p>C# 14 introduces extension blocks, which let you add not just methods, but properties and static members to existing types.</p><p>With classic extension methods, you can only add methods. They always look like method calls:</p><pre><code class="language-csharp">public static class DeliveryOrderExtensions
{
    public static bool IsUrgent(this DeliveryOrder order)
        =&gt; order.DeliveryDate &lt;= DateOnly.FromDateTime(DateTime.Today.AddDays(1));

    public static TimeSpan GetWindowDuration(this DeliveryOrder order)
        =&gt; order.WindowEnd.ToTimeSpan() - order.WindowStart.ToTimeSpan();
}
</code></pre><p>With no way to define extension properties, we have to use <code>GetWindowDuration()</code> instead of just <code>WindowDuration</code>.</p><p>C# 14 extension blocks change this. (Yes, I don't like the syntax either; don't kill the messenger!)</p><pre><code class="language-csharp">public static class DeliveryExtensions
{
    extension(DeliveryOrder order)
    {
        public bool IsUrgent
            =&gt; order.DeliveryDate &lt;= DateOnly.FromDateTime(DateTime.Today.AddDays(1));

        public TimeSpan WindowDuration
            =&gt; order.WindowEnd.ToTimeSpan() - order.WindowStart.ToTimeSpan();

        public bool FitsChimney(double santaWidth, double santaHeight)
            =&gt; order.Chimney.WidthInches &gt;= santaWidth &amp;&amp;
               order.Chimney.HeightInches &gt;= santaHeight;

        public string ToManifestLine()
            =&gt; $"{order.GiftId}|{order.AssignedElf}|{order.OriginWorkshop}|" +
               $"{order.DeliveryDate:yyyy-MM-dd}|{order.WindowStart:HH:mm}|" +
               $"{order.WindowEnd:HH:mm}|{order.Chimney}|{order.RecipientName}|" +
               $"{order.Address}";
    }

    extension(DateOnly)
    {
        public static DateOnly ChristmasThisYear
            =&gt; new(DateTime.Today.Year, 12, 25);

        public static DateOnly NextChristmas()
        {
            var today     = DateOnly.FromDateTime(DateTime.Today);
            var christmas = new DateOnly(today.Year, 12, 25);

            return today &gt; christmas
                ? new DateOnly(today.Year + 1, 12, 25)
                : christmas;
        }
    }
}</code></pre><p>Now we can use extension properties like native properties—even more, static extensions appear directly on the type.</p><pre><code class="language-csharp">var order = new DeliveryOrder
{
    GiftId        = new GiftId(123),
    AssignedElf   = new ElfId(42),
    OriginWorkshop= new WorkshopId(3),
    DeliveryDate  = DateOnly.FromDateTime(DateTime.Today),
    WindowStart   = new TimeOnly(23, 0),
    WindowEnd     = new TimeOnly(23, 30),
    Chimney       = new ChimneyDimensions(24, 36),
    RecipientName = "Charlie",
    Address       = "123 Candy Cane Lane"
};

if (order.IsUrgent)
{
    Console.WriteLine($"Rush delivery! Window: {order.WindowDuration}");
}

if (order.FitsChimney(20, 24))
{
    Console.WriteLine("Santa approved!");
}

var christmas = DateOnly.ChristmasThisYear;
var next      = DateOnly.NextChristmas();</code></pre><p><code>IsUrgent</code> and <code>WindowDuration</code> are properties now, and <code>ChristmasThisYear</code> looks like it's built into <code>DateOnly</code>.</p><h2 id="putting-it-all-together">Putting it all together</h2><p>Finally! Here's our modernized <code>DeliveryOrder</code> that uses everything we discussed.</p><pre><code class="language-csharp">public record DeliveryOrder
{
    public required GiftId GiftId { get; init; }
    public required ElfId AssignedElf { get; init; }
    public required WorkshopId OriginWorkshop { get; init; }
    public required DateOnly DeliveryDate { get; init; }
    public required TimeOnly WindowStart { get; init; }
    public required TimeOnly WindowEnd { get; init; }
    public required ChimneyDimensions Chimney { get; init; }
    public required string RecipientName { get; init; }
    public required string Address { get; init; }
}</code></pre><p>Everything we wanted is more explicit:</p><ul><li><strong>Strongly-typed IDs</strong>: we can't mix up <code>GiftId</code> with <code>ElfId</code></li><li><strong>Clear date/time semantics</strong>: <code>DateOnly</code> for dates, <code>TimeOnly</code> for times</li><li><strong>Efficient parsing</strong>: <code>IParsable&lt;TSelf&gt;</code> and <code>ISpanParsable&lt;TSelf&gt;</code> let us share parsing logic and avoid allocations in hot paths</li><li><strong>Practical APIs</strong>: C# 14 extension members let us hang useful behavior (like <code>IsUrgent</code> and <code>ToManifestLine</code>) right off our domain types.</li></ul><p>Think of these features as guardrails: they let the compiler catch mistakes that used to be runtime bugs — and they do it with zero or negligible runtime overhead.</p><p>Thanks for reading, happy holidays, and most importantly: happy parsing! 🎅</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Extension Properties: C# 14&#x27;s Game-Changing Feature for Cleaner Code ]]></title>
        <description><![CDATA[ This post was originally published on the Telerik Developer Blog.

Since C# 3 dropped in 2007, C# developers have been using extension methods to add functionality to types without touching their source code. Whether you&#39;re extending types from the .NET BCL, third-party libraries, or even your own legacy ]]></description>
        <link>https://www.daveabrock.com/2025/12/05/extension-properties-c-14s-game-changing-feature-for-cleaner-code/</link>
        <guid isPermaLink="false">690534ca52532b00018149b6</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 05 Dec 2025 14:43:45 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1563453392212-326f5e854473?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDF8fGNsZWFufGVufDB8fHx8MTc2MTk0ODg2OXww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post was originally published on the </em><a href="https://www.telerik.com/blogs/extension-properties-csharp-14-game-changing-feature-cleaner-code?ref=daveabrock.com" rel="noreferrer"><em>Telerik Developer Blog</em></a><em>.</em></p><p>Since C# 3 dropped in 2007, C# developers have been using extension methods to add functionality to types without touching their source code. Whether you're extending types from the .NET BCL, third-party libraries, or even your own legacy code, extension methods have been essential to how we write C# code.</p><p>But there's always been one big limitation: you can only extend methods, not properties. The community <a href="https://stackoverflow.com/questions/619033/does-c-sharp-have-extension-properties?ref=daveabrock.com" rel="noreferrer">has been impatiently waiting</a> for that day to come.</p><p>With C# 14, that's about to change. Soon to ship with .NET 10 on November 11, 2025, Microsoft is introducing <a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods?ref=daveabrock.com" rel="noreferrer">extension members</a>, an expansion of the extension pattern that brings extension properties, extension indexers, and even static extension members to the language. </p><h2 id="a-quick-primer-on-extension-methods">A quick primer on extension methods</h2><p>Let's make sure we're all on the same page. Extension methods let you "add" methods to existing types without modifying them or creating derived types.</p><p>Here's a classic example:</p><pre><code class="language-csharp">public static class StringExtensions
{
    // Note the 'this' keyword on the first parameter
    public static string Capitalize(this string value)
    {
        if (string.IsNullOrEmpty(value))
            return value;
        return char.ToUpper(value[0]) + value.Substring(1).ToLower();
    }
}

// We call it as if it's an instance method of string
string name = "sara";
string capitalized = name.Capitalize(); // Returns "Sara"</code></pre><p>The magic happens with the <code>this</code> keyword on the first parameter, which tells the compiler this is an extension method. Even though <code>Capitalize</code> is a static method in a static class, you call it as if it is an instance method on the string type (which we call the receiver type). IntelliSense picks it up and everyone's happy.</p><p>Extension methods are a core part of the .NET ecosystem and can be found in virtually every code base. For example, the classic LINQ methods like <code>Where</code>, <code>Select</code>, and <code>OrderBy</code> are all extension methods that make collections feel like they have built-in query capabilities. Even so, they are not without their limitations.</p><h2 id="limitations-of-extension-methods">Limitations of extension methods</h2><p>We all love extension methods — however, extension methods have always been limited to ... well, methods. </p><p>Let's say you're working with an API client and you're working with HTTP responses all day. You find yourself constantly checking status codes:</p><pre><code class="language-csharp">var response = await httpClient.GetAsync(url);

if ((int)response.StatusCode &gt;= 200 &amp;&amp; (int)response.StatusCode &lt; 300)
{
    Console.WriteLine("Success!");
}
else if ((int)response.StatusCode &gt;= 400 &amp;&amp; (int)response.StatusCode &lt; 500)
{
    Console.WriteLine("Client error - check your request");
}</code></pre><p>That's ... not great. So you do what any good C# developer would do: create extension methods.</p><pre><code class="language-csharp">public static class HttpStatusCodeExtensions
{
    public static bool IsSuccess(this HttpStatusCode status)
    {
        return (int)status &gt;= 200 &amp;&amp; (int)status &lt; 300;
    }
    
    public static bool IsClientError(this HttpStatusCode status)
    {
        return (int)status &gt;= 400 &amp;&amp; (int)status &lt; 500;
    }
}

if (response.StatusCode.IsSuccess())
{
    Console.WriteLine("Success!");
}</code></pre><p>This is <em>better</em>, but something feels off. You're calling <code>IsSuccess()</code> with parentheses, like it's doing work. But it's not really an action, it's a characteristic of the status code. It cries out "what are you?" and not "what can you do?"</p><p>At the risk of going back to CS101, methods represent actions and properties represent attributes and characteristics. When you want to know if a number is positive, you don't call <code>number.IsPositive()</code>. You'd naturally expect <code>number.IsPositive</code>.</p><p>For almost two decades, we've been writing methods when we wanted properties. We've added <code>Get</code> prefixes, used parentheses where they don't belong, and generally worked around this limitation. </p><h2 id="extension-members-in-c-14">Extension members in C# 14</h2><p>C# 14 addresses this limitation with extension members. This new syntax introduces a dedicated <code>extension</code> block that allows you to define multiple kinds of extension members for a type, including properties, indexers, and static members.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">Your extension methods aren't going anywhere and will continue to work in C# 14 in beyond. You'll be able to use static extension methods, and the <code spellcheck="false" style="white-space: pre-wrap;">this</code> keyword as you have before.</div></div><p>Here's how it works. Instead of individual extension methods, you create an <code>extension</code> block.</p><pre><code class="language-csharp">public static class HttpStatusCodeExtensions
{
    extension(HttpStatusCode status)
    {
        public bool IsSuccess =&gt; (int)status &gt;= 200 &amp;&amp; (int)status &lt; 300;
        public bool IsRedirect =&gt; (int)status &gt;= 300 &amp;&amp; (int)status &lt; 400;
        public bool IsClientError =&gt; (int)status &gt;= 400 &amp;&amp; (int)status &lt; 500;
        public bool IsServerError =&gt; (int)status &gt;= 500 &amp;&amp; (int)status &lt; 600;
    }
}

var response = await httpClient.GetAsync(url);
if (response.StatusCode.IsSuccess)
{
    Console.WriteLine("Success!");
}
else if (response.StatusCode.IsClientError)
{
    Console.WriteLine("Client error - check your request");
}</code></pre><p>Look at that. No parentheses. It reads like <code>IsSuccess</code> is an actual property of <code>HttpStatusCode</code>. Because now it <em>is</em>.</p><p>The <code>extension</code> declaration creates a block where <code>status</code> is your receiver (the instance you're extending). Everything inside can access <code>status</code> just like you'd access <code>this</code> in a regular class.</p><h2 id="about-that-syntax">About that syntax...</h2><p>I probably should have warned you about the <code>extension</code> block. That might take some getting used to, <a href="https://www.reddit.com/r/csharp/comments/1mwglrp/c_14_and_extension_member_thoughts/?ref=daveabrock.com" rel="noreferrer">and I'm not alone</a>. Many developers find it ugly and verbose, and I did at first. But much like the <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression?ref=daveabrock.com" rel="noreferrer">switch expression syntax</a>, it's growing on me. (And after waiting almost two decades for this, I'll take what I can get.)</p><p>Plus, once you group related extension members together, it starts to make sense:</p><pre><code class="language-csharp">extension(HttpStatusCode status)
{
    // Properties for checking categories
    public bool IsSuccess =&gt; (int)status &gt;= 200 &amp;&amp; (int)status &lt; 300;
    public bool IsClientError =&gt; (int)status &gt;= 400 &amp;&amp; (int)status &lt; 500;
    
    // Property that uses other extension properties
    public string Category =&gt; status switch
    {
        _ when status.IsSuccess =&gt; "Success",
        _ when status.IsClientError =&gt; "Client Error",
        _ =&gt; "Unknown"
    };
}</code></pre><p>In this example, everything related to <code>HttpStatusCode</code> extensions lives in one place.</p><p>According <a href="https://devblogs.microsoft.com/dotnet/csharp-exploring-extension-members/?ref=daveabrock.com" rel="noreferrer">to the C# team</a>, they explored many different design considerations: putting the receiver on every member (too repetitive), attaching the receiver to the static class (breaks existing patterns), extending <code>this</code> for properties (just, no), or other approaches that had breaking changes or complicated implementations.</p><p>The <code>extension</code> block won out because it doesn't break existing code (your regular extension methods keep working), it's flexible, allows grouping, and provides a place for the receiver to live. After all, since properties don't have parameters, where else would you declare a type you're extending?</p><h2 id="even-better-static-extension-members">Even better: Static extension members</h2><p>Why stop there? This new feature supports static extension members, opening up new patterns for extending types. </p><p>You can define static extension members in an extension block without a receiver instance.</p><p>Let's add some factory methods and constants to <code>HttpStatusCode</code> :</p><pre><code class="language-csharp">public static class HttpStatusCodeExtensions
{
    // Static extension members - no instance needed
    extension(HttpStatusCode)
    {
        public static DefaultHttpStatusCode OK =&gt; HttpStatusCode.OK;
        public static DefaultHttpStatusCode NotFound =&gt; HttpStatusCode.NotFound;
        public static DefaultHttpStatusCode BadRequest =&gt; HttpStatusCode.BadRequest;
        
        public static HttpStatusCode FromInt(int code) =&gt; (HttpStatusCode)code;
    }
}

// Use them like built-in static members
var status = HttpStatusCode.DefaultOK;
var notFound = HttpStatusCode.DefaultNotFound;
var teapot = HttpStatusCode.FromInt(418); // I'm a teapot!</code></pre><p>Notice the difference here? No receiver instance is in the extension declaration, just <code>extension(HttpStatusCode)</code>. This lets you add static members that feel like they belong to the type itself.</p><p>This is perfect for factory patterns, type-specific constants, or utility methods that don't need an instance.</p><h2 id="building-a-complete-solution">Building a complete solution</h2><p>Let's put it all together and build something useful. We'll create a full set of extension members for working with HTTP status codes:</p><pre><code class="language-csharp">public static class HttpStatusCodeExtensions
{
    // Static extension members for common codes
    extension(HttpStatusCode)
    {
        public static DefaultHttpStatusCode OK =&gt; HttpStatusCode.OK;
        public static DefaultHttpStatusCode NotFound =&gt; HttpStatusCode.NotFound;
        public static DefaultHttpStatusCode BadRequest =&gt; HttpStatusCode.BadRequest;
        public static HttpStatusCode FromInt(int code) =&gt; (HttpStatusCode)code;
    }
    
    // Instance extension properties
    extension(HttpStatusCode status)
    {
        public bool IsSuccess =&gt; (int)status &gt;= 200 &amp;&amp; (int)status &lt; 300;
        public bool IsRedirect =&gt; (int)status &gt;= 300 &amp;&amp; (int)status &lt; 400;
        public bool IsClientError =&gt; (int)status &gt;= 400 &amp;&amp; (int)status &lt; 500;
        public bool IsServerError =&gt; (int)status &gt;= 500 &amp;&amp; (int)status &lt; 600;
        
        public string Category =&gt; status switch
        {
            _ when status.IsSuccess =&gt; "Success",
            _ when status.IsRedirect =&gt; "Redirect",
            _ when status.IsClientError =&gt; "Client Error",
            _ when status.IsServerError =&gt; "Server Error",
            _ =&gt; "Unknown"
        };
    }
}</code></pre><p>Now look at how clean your HTTP client code becomes:</p><pre><code class="language-csharp">var response = await httpClient.GetAsync(url);

if (response.StatusCode.IsSuccess)
{
    var data = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"Success! Category: {response.StatusCode.Category}");
}
else if (response.StatusCode.IsClientError)
{
    Console.WriteLine("Client error - check your request");
}
else if (response.StatusCode.IsServerError)
{
    Console.WriteLine("Server error - try again later");
}</code></pre><h2 id="more-real-world-examples">More "real world" examples</h2><p>Once you start working through extension properties, you'll find uses everywhere.</p><h3 id="string-validation">String validation</h3><pre><code class="language-csharp">public static class StringExtensions
{
    extension(string str)
    {
        public bool IsEmpty =&gt; string.IsNullOrEmpty(str);
        public bool IsWhitespace =&gt; string.IsNullOrWhiteSpace(str);
        public bool IsValidEmail =&gt; !str.IsEmpty &amp;&amp; 
            str.Contains("@") &amp;&amp; str.Contains(".");
        public bool IsNumeric =&gt; !str.IsEmpty &amp;&amp; str.All(char.IsDigit);
    }
}

string email = "sara@peloton.com";
if (!email.IsEmpty &amp;&amp; email.IsValidEmail)
{
    Console.WriteLine("Valid email!");
}</code></pre><h3 id="collection-helpers">Collection helpers</h3><pre><code class="language-csharp">public static class CollectionExtensions
{
    extension&lt;T&gt;(ICollection&lt;T&gt; collection)
    {
        public bool IsEmpty =&gt; collection.Count == 0;
        public bool HasMultipleItems =&gt; collection.Count &gt; 1;
        public bool HasSingleItem =&gt; collection.Count == 1;
    }
}

var items = new List&lt;string&gt; { "apple", "banana" };

// No more items.Count &gt; 1
if (items.HasMultipleItems)
{
    Console.WriteLine("Multiple items found");
}</code></pre><h3 id="checking-state-of-async-tasks">Checking state of async tasks</h3><pre><code class="language-csharp">public static class TaskExtensions
{
    extension&lt;T&gt;(Task&lt;T&gt;)
    {
        public static Task&lt;T&gt; FromCancellation =&gt; 
            Task.FromCanceled&lt;T&gt;(new CancellationToken(true));
        
        public static Task&lt;T&gt; FromValue(T result) =&gt; 
            Task.FromResult(result);
    }
    
    extension&lt;T&gt;(Task&lt;T&gt; task)
    {
        public bool IsSuccessful =&gt; task.IsCompletedSuccessfully;
        public bool HasFailed =&gt; task.IsFaulted;
        public Exception? Error =&gt; task.Exception?.InnerException;
    }
}

// Usage
var task = Task.FromValue(42);
if (task.IsSuccessful)
{
    Console.WriteLine("All done!");
}</code></pre><h2 id="what-about-performance">What about performance?</h2><p>You're right to question performance with new language features. Luckily, extension members are syntactic sugar that compiles down to regular method calls, just like traditional extension methods. The CLR doesn't know (or care) that you used extension syntax.</p><p>Accessing <code>response.StatusCode.IsSuccess</code> generates identical IL code to calling an <code>IsSuccess()</code> method. </p><h2 id="a-few-gotchas">A few gotchas</h2><p>While extension members are great, you'll want to know about a few limitations:</p><ul><li><strong>No extension fields</strong>. You can't add fields to types through extensions; this means auto-properties like <code>public string Status { get; set; }</code> won't work because they technically require backing fields.</li><li><strong>Generic type parameter order. </strong>If the type isn't in the "receiver first, method second" order, it can't use the new syntax. I'd say this is rare, but if you have something like <code>SelectLessThan&lt;TResult, T&gt;</code> it'll have to stay as an extension method.</li></ul><h2 id="what-this-means-for-your-code">What this means for your code</h2><p>Extension members, to me, aren't just a nice-to-have feature. They change how we think about extending C# types.</p><p>Think of API design: when you're writing libraries, you can provide extension points that finally feel like part of the type. Users won't have to remember if something is a method or a property. It'll be whatever makes most sense.</p><h2 id="wrapping-up">Wrapping up</h2><p>With C# 14 and .NET 10, we <em>finally </em>have extension properties. We can now extend types with the syntax that makes sense. We can stop pretending that characteristics are actions.</p><p>Is the <code>extension</code> block weird and different? Yes. Will we get used to it? Probably.</p><p>How will you use extension members? Let me know in the comments, and happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 6: Deployment Using Azure Container Apps ]]></title>
        <description><![CDATA[ The .NET Aspire series continues with deploying to Azure Container Apps. Using the Azure Developer CLI, we explore how to deploy to the cloud and also explore deployment considerations when pushing to production. ]]></description>
        <link>https://www.daveabrock.com/2025/10/21/net-aspire-6-deployment-using-azure-container-apps/</link>
        <guid isPermaLink="false">68f7ca9a353aec0001640f12</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 21 Oct 2025 13:06:10 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1517728848779-e95acb6ac40f?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDF8fHJlbGVhc2V8ZW58MHx8fHwxNzYxMDY5OTIxfDA&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published in the <a href="https://www.telerik.com/blogs/net-aspire-6-deployment-using-azure-container-apps?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p><em>This is the final part of our six‑part deep dive into .NET Aspire.</em></p><ul><li>Part 1:&nbsp;What Is .NET Aspire?</li><li>Part 2:&nbsp;Exploring the Developer Dashboard</li><li>Part 3:&nbsp;Service Defaults</li><li>Part 4:&nbsp;Integrations</li><li>Part 5:&nbsp;Orchestration &amp; Service Discovery</li><li><strong>This post (Part 6)</strong>: Deployment Using Azure Container Apps</li></ul><p>Welcome back. Time to ship this thing.</p><p>During this series, we’ve gone from learning&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-1-what-is-net-aspire?ref=daveabrock.com">what .NET Aspire is</a>, to&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-2-developer-dashboard?ref=daveabrock.com">exploring the dashboard</a>, and&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-3-service-defaults?ref=daveabrock.com">service defaults</a>,&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-4-integrations?ref=daveabrock.com">integrations</a>&nbsp;and&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-5-orchestration-service-discovery?ref=daveabrock.com">service discovery</a>.</p><p>If you’ve been coding along, you’ve probably enjoyed how Aspire makes local development approachable. We’ve spun up APIs, databases, a Blazor frontend and a Redis cache and watched them all come alive in a single “mission control” dashboard.</p><p>But production doesn’t run on&nbsp;<em>localhost:5000</em>&nbsp;(trust me, I’ve tried). Today, we’re deploying Azure Container Apps using the Azure Developer CLI (<code>azd</code>), and I will show you how the proverbial sausage gets made.</p><h2 id="the-evolving-deployment-story">The Evolving Deployment Story</h2><p>Since the initial release of Aspire, the deployment story has significantly matured. With Aspire 9.2 and later, Microsoft&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9.2?ref=daveabrock.com#-deployment-improvements">introduced a new publishing model</a>&nbsp;that gives you more flexibility in how and where you deploy your applications.</p><p>The original process generates a manifest file that the&nbsp;<code>azd</code>&nbsp;CLI consumes to provision infrastructure. This is great for Azure deployments but is very opaque.</p><p>Aspire 9.2 and later introduces the&nbsp;<code>aspire publish</code>&nbsp;and&nbsp;<code>aspire deploy</code>&nbsp;commands with extensible publishers. With this new process, you can now generate Docker Compose files, Kubernetes manifests, Bicep templates or even custom publishers. While the manifest format still exists, many are favoring this more flexible approach.</p><p>For Azure deployments specifically,&nbsp;<code>azd</code>&nbsp;remains the recommended path and is what we’ll use in this article. It has first-class Aspire support and handles the entire workflow from provisioning to deployment. If you need more extensibility, consider the publisher model.</p><h2 id="why-are-we-deploying-to-azure-container-apps">Why Are We Deploying to Azure Container Apps?</h2><p>If you’ve reached this point, you might be asking: why ACA? After all, we could throw our Aspire services on a VM, App Service, Azure Kubernetes Service (AKS) or even good old IIS.</p><p>Here’s why ACA and Aspire make sense for us:</p><ul><li><strong>Serverless containers.</strong>&nbsp;With ACA, we don’t manage VMs or clusters. ACA scales your containers based on demand. Because Aspire apps are often microservice-y by nature, ACA fits us well.</li><li><strong>Built-in Dapr support.</strong>&nbsp;Aspire&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/community-toolkit/dapr?tabs=dotnet-cli&ref=daveabrock.com">leans on Dapr</a>&nbsp;for service-to-service communication and other benefits. ACA lets you enable Dapr sidecars with a single setting, which is less plumbing that we need to maintain.</li></ul><p>Don’t worry, I’m not getting paid by Microsoft. It’s not all sunshine and rainbows. Aside from the obvious vendor lock-in, ACA also comes with:</p><ul><li><strong>Opaque scaling rules.</strong>&nbsp;ACA’s autoscaling works well, but in many cases tuning it can feel like trial and error. You’ll need to experiment and test thoroughly to avoid cold starts or runaway costs.</li><li><strong>Debugging complexity.</strong>&nbsp;While the local Aspire dashboard is great to use, debugging distributed Aspire services running in ACA is less so. While logging and observability help, the gap is real.</li></ul><p>ACA is definitely Azure’s fastest path to the cloud. You trade some control for simplicity. Depending on your goals, that may be a fair tradeoff.</p><h2 id="the-database-question-to-containerize-in-the-cloud-or-not">The Database Question: To Containerize in the Cloud or Not?</h2><p>For local development, Aspire apps typically run SQL Server in a container. This makes complete sense: you need a database to develop against, and containerized SQL spins up quickly alongside your APIs.</p><p>But when you move to production, you need to make a decision: containerize the database or use a managed service?</p><p><strong>If you decide to containerize SQL server</strong>, you see:</p><ul><li>A familiar setup, just like locally</li><li>Everything runs in containers, giving you symmetry between local development and your cloud environments</li><li>That it’s fast to set up and tear down</li></ul><p>However, you’ll see some drawbacks:</p><ul><li>Persistence becomes your problem. Unless you’ve carefully configured volumes, you risk losing data when you restart the container</li><li>Congratulations, you are now responsible for patching, scaling, backups and high availability</li><li>Databases are stateful; ACA is best for stateless workloads</li></ul><p>If you&nbsp;<strong>decide to use an Azure SQL Database</strong>, you see:</p><ul><li>A fully managed database: backups, scaling and security patches are all managed by Microsoft</li><li>High availability out of the box</li><li>It integrates with managed identity, preventing manual management of passwords and tokens</li></ul><p>Some drawbacks:</p><ul><li>It costs more than a containerized SQL instance</li><li>It isn’t “free” to tear down and spin up like a container</li><li>Some features differ from full SQL Server (though for most use cases, it’s a non-issue)</li></ul><p>In my experience, most teams run containerized SQL for development and Azure SQL (or another managed cloud database) for production use cases. Aspire does make this easy; just point your connection string to Azure SQL instead of a container. With&nbsp;<code>DefaultAzureCredential</code>, your app can authenticate securely without storing a password.</p><p>A pragmatic path is usually best. When it comes to production, databases are too critical to treat as disposable containers.</p><h2 id="prepare-aspire-services-for-deployment">Prepare Aspire Services for Deployment</h2><p>Your Aspire solution likely has several components. For what we’ve developed in this series, we have:</p><ul><li><strong>Inventory API:</strong>&nbsp;Tracks in-stock guitars</li><li><strong>Orders API:</strong>&nbsp;Places customer orders and validates stock against Inventory</li><li><strong>Blazor frontend:</strong>&nbsp;The user interface that calls the API behind the scenes</li><li><strong>Redis cache:</strong>&nbsp;A cache that speeds up reads in our Blazor app</li><li><strong>SQL database:</strong>&nbsp;Our database layer (we’ll be using Azure SQL for production)</li></ul><p>Locally, Aspire’s&nbsp;<code>AppHost</code>&nbsp;orchestrates all these. But in ACA, each service becomes its own container with its own lifecycle.</p><p>This changes a few things:</p><ul><li><strong>Networking.</strong>&nbsp;Locally, Aspire wires up services with simple hostnames. In ACA, we’ll learn on Dapr service IDs or ACA-managed DNS.</li><li><strong>Configuration.</strong>&nbsp;Locally,&nbsp;<code>appsettings.json</code>&nbsp;or&nbsp;<code>secrets.json</code>&nbsp;carries secrets. In ACA, our secrets will come from Azure Key Vault or ACA environment variables.</li><li><strong>Scaling.</strong>&nbsp;Locally, everything runs together. In ACA, each service can scale independently. For example, our Inventory API may need more replicas than our Blazor app.</li></ul><p>While Aspire gives us the glue to hold our services together, we still need to think of each service as independently deployable.</p><h2 id="deploy-with-azd-the-happy-path">Deploy with azd: The Happy Path</h2><p>With our deployment, everything starts with&nbsp;<code>azd init</code>, which provides customized support for .NET Aspire projects. To get started, you’ll need to&nbsp;<a href="https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd?ref=daveabrock.com">install the Azure Developer CLI</a>.</p><p>This diagram,&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/deployment/azd/aca-deployment-azd-in-depth?ref=daveabrock.com">respectfully stolen from the Microsoft documentation</a>, gives a great overview of how&nbsp;<code>azd</code>&nbsp;runs its deployments.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-10/azd-integration.png?sfvrsn=2cc59927_2" class="kg-image" alt="azd integration" loading="lazy" width="3870" height="2167"></figure><p>For more in-depth details, please&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/deployment/azd/aca-deployment-azd-in-depth?ref=daveabrock.com">check out the docs</a>. To simplify:&nbsp;<code>azd</code>&nbsp;produces an Aspire&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/deployment/manifest-format?ref=daveabrock.com">manifest file</a>, the&nbsp;<code>azd provision</code>&nbsp;call generates Bicep files, a deployment triggers using Azure Resource Manager (ARM) APIs,&nbsp;<code>azd deploy</code>&nbsp;executes with the same manifest file,&nbsp;<code>azd</code>&nbsp;makes a call to&nbsp;<code>dotnet publish</code>&nbsp;to generate container images,&nbsp;<code>azd</code>&nbsp;pushes images to an ACR registry, and, finally,&nbsp;<code>azd</code>&nbsp;uses the new version of the image.</p><p>Let’s walk through a successful deployment. I’ll walk through the commands and explain what’s happening at each step.</p><h3 id="step-1-initialize-the-project">Step 1: Initialize the Project</h3><p>From your root directory (where your .sln file lives):</p><pre><code class="language-bash">azd init
</code></pre><p>You’ll see the following prompt:</p><pre><code class="language-bash">? How do you want to initialize your app?
&gt; Use code in the current directory
  Select a template
</code></pre><p>We’ll select&nbsp;<strong>Use code in the current directory</strong>. Next,&nbsp;<code>azd</code>&nbsp;scans your directory and detects your&nbsp;<code>AppHost</code>&nbsp;project:</p><pre><code class="language-bash">Detected services:

  .NET (Aspire)
  Detected in: C:\code\AspireGuitarShop\AspireGuitarShop.AppHost\AspireGuitarShop.AppHost.csproj

azd will generate the files necessary to host your app on Azure using Azure Container Apps.

? Select an option
&gt; Confirm and continue initializing my app
  Cancel and exit
</code></pre><p>Select&nbsp;<strong>Confirm and continue initializing my app</strong>. Then, enter an environment name (like&nbsp;<code>dev</code>&nbsp;or&nbsp;<code>production</code>).</p><pre><code class="language-bash">? Enter a unique environment name: dev

Generating files to run your app on Azure:

  (✓) Done: Generating ./azure.yaml
  (✓) Done: Generating ./next-steps.md

SUCCESS: Your app is ready for the cloud!
You can provision and deploy your app to Azure by running the azd up command in this directory.
</code></pre><p>This creates several files:</p><ul><li><code>azure.yaml</code>&nbsp;describes the services</li><li><code>.azure/config.json</code>&nbsp;stores the environment configuration</li><li><code>.azure/dev/.env</code>&nbsp;contains environment-specific settings</li></ul><h3 id="step-2-deploy-to-azure">Step 2: Deploy to Azure</h3><p>Enter this simple command:</p><pre><code class="language-bash">azd up
</code></pre><p>With this single command,&nbsp;<code>azd</code>:</p><ul><li>Authenticates you to Azure</li><li>Prompts you for your subscription and location</li><li>Provisions your Azure resources</li><li>Builds and pushes your container images</li><li>Deploys your services</li></ul><p>You’ll see output like the following:</p><pre><code class="language-bash">? Select an Azure Subscription to use:
&gt; 1. Your Subscription (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

? Select an Azure location to use:
&gt; 44. (US) East US 2 (eastus2)

? Select which services to expose to the Internet
&gt; frontend

Packaging services (azd package)

Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

  Subscription: Your Subscription
  Location: East US 2

  (✓) Done: Resource group: rg-dev-xxxx
  (✓) Done: Container Registry: crdevxxxx
  (✓) Done: Log Analytics workspace: log-dev-xxxx
  (✓) Done: Container Apps Environment: cae-dev-xxxx

SUCCESS: Your application was provisioned in Azure in 1 minute 13 seconds.

Deploying services (azd deploy)

  (✓) Done: Deploying service inventoryapi
    - Endpoint: inventoryapi.xxxx.eastus2.azurecontainerapps.io/

  (✓) Done: Deploying service ordersapi
    - Endpoint: ordersapi.xxxx.eastus2.azurecontainerapps.io/

  (✓) Done: Deploying service frontend
    - Endpoint: frontend.xxxx.eastus2.azurecontainerapps.io/

  Aspire Dashboard: https://dashboard.xxxx.eastus2.azurecontainerapps.io/

SUCCESS: Your up workflow to provision and deploy to Azure completed in 3 minutes 50 seconds.
</code></pre><p>Do you see the link to the Aspire dashboard at the bottom? This is fully supported as of Aspire 9.2, giving you the same experience in production that you have in your local environment.</p><h3 id="what-azd-deployed">What azd Deployed</h3><p>If we navigate to the Azure portal, we’ll see:</p><ul><li><strong>Container registry:</strong>&nbsp;A repository for our container images. Each of our services (Inventory API, Orders API, Frontend) gets pushed here as a container image.</li><li><strong>Log analytics workspace:</strong>&nbsp;Collects logs and metrics from all our services. This feeds into Application Insights.</li><li><strong>Container apps environment:</strong>&nbsp;The logical boundary for our Container Apps (think of it as a cluster that the containers run in).</li><li><strong>Individual container apps:</strong>&nbsp;We have one for each service in our&nbsp;<code>AppHost</code>. Because of this, each Container App scales independently.</li><li><strong>Managed identities:</strong>&nbsp;With Aspire 9.2, each Container App gets its own managed identity by default.</li></ul><h3 id="the-bicep-layer">The Bicep layer</h3><p>Behind the scenes,&nbsp;<code>azd</code>&nbsp;generated Bicep templates to provision our infrastructure. We can generate them explicitly with the following command:</p><pre><code class="language-bash">azd infra generate
</code></pre><p>This generates an&nbsp;<code>infra</code>&nbsp;folder with Bicep files. What’s inside?</p><p>First is a&nbsp;<em>main.bicep</em>&nbsp;file that orchestrates the entire deployment. It creates the resource group and calls other modules.</p><pre><code class="language-bicep">targetScope = 'subscription'

@minLength(1)
@maxLength(64)
@description('Name of the environment that can be used as part of naming resource convention, the name of the resource group for your application will use this name, prefixed with rg-')
param environmentName string

@minLength(1)
@description('The location used for all deployed resources')
param location string

@description('Id of the user or app to assign application roles')
param principalId string = ''

@metadata({azd: {
  type: 'generate'
  config: {length:22,noSpecial:true}
  }
})
@secure()
param cache_password string
@secure()
param password string

var tags = {
  'azd-env-name': environmentName
}

resource rg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
  name: 'rg-${environmentName}'
  location: location
  tags: tags
}
module resources 'resources.bicep' = {
  scope: rg
  name: 'resources'
  params: {
    location: location
    tags: tags
    principalId: principalId
  }
}


output MANAGED_IDENTITY_CLIENT_ID string = resources.outputs.MANAGED_IDENTITY_CLIENT_ID
output MANAGED_IDENTITY_NAME string = resources.outputs.MANAGED_IDENTITY_NAME
output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = resources.outputs.AZURE_LOG_ANALYTICS_WORKSPACE_NAME
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = resources.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT
output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = resources.outputs.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID
output AZURE_CONTAINER_REGISTRY_NAME string = resources.outputs.AZURE_CONTAINER_REGISTRY_NAME
output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_NAME
output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID
output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN
output SERVICE_SERVER_VOLUME_GUITARDATA_NAME string = resources.outputs.SERVICE_SERVER_VOLUME_GUITARDATA_NAME
output AZURE_VOLUMES_STORAGE_ACCOUNT string = resources.outputs.AZURE_VOLUMES_STORAGE_ACCOUNT
</code></pre><p>Next, we have&nbsp;<em>resources.bicep</em>. This file defines the actual Azure resources.</p><pre><code class="language-bicep">@description('The location used for all deployed resources')
param location string = resourceGroup().location
@description('Id of the user or app to assign application roles')
param principalId string = ''


@description('Tags that will be applied to all resources')
param tags object = {}

var resourceToken = uniqueString(resourceGroup().id)

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'mi-${resourceToken}'
  location: location
  tags: tags
}

resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
  name: replace('acr-${resourceToken}', '-', '')
  location: location
  sku: {
    name: 'Basic'
  }
  tags: tags
}

resource caeMiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(containerRegistry.id, managedIdentity.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
  scope: containerRegistry
  properties: {
    principalId: managedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
    roleDefinitionId:  subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
  }
}

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
  name: 'law-${resourceToken}'
  location: location
  properties: {
    sku: {
      name: 'PerGB2018'
    }
  }
  tags: tags
}

resource storageVolume 'Microsoft.Storage/storageAccounts@2022-05-01' = {
  name: 'vol${resourceToken}'
  location: location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
  properties: {
    largeFileSharesState: 'Enabled'
  }
}

resource storageVolumeFileService 'Microsoft.Storage/storageAccounts/fileServices@2022-05-01' = {
  parent: storageVolume
  name: 'default'
}

resource serverGuitarDataFileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2022-05-01' = {
  parent: storageVolumeFileService
  name: take('${toLower('server')}-${toLower('guitardata')}', 60)
  properties: {
    shareQuota: 1024
    enabledProtocols: 'SMB'
  }
}

resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2024-02-02-preview' = {
  name: 'cae-${resourceToken}'
  location: location
  properties: {
    workloadProfiles: [{
      workloadProfileType: 'Consumption'
      name: 'consumption'
    }]
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalyticsWorkspace.properties.customerId
        sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
      }
    }
  }
  tags: tags

  resource aspireDashboard 'dotNetComponents' = {
    name: 'aspire-dashboard'
    properties: {
      componentType: 'AspireDashboard'
    }
  }

}

resource serverGuitarDataStore 'Microsoft.App/managedEnvironments/storages@2023-05-01' = {
  parent: containerAppEnvironment
  name: take('${toLower('server')}-${toLower('guitardata')}', 32)
  properties: {
    azureFile: {
      shareName: serverGuitarDataFileShare.name
      accountName: storageVolume.name
      accountKey: storageVolume.listKeys().keys[0].value
      accessMode: 'ReadWrite'
    }
  }
}

output MANAGED_IDENTITY_CLIENT_ID string = managedIdentity.properties.clientId
output MANAGED_IDENTITY_NAME string = managedIdentity.name
output MANAGED_IDENTITY_PRINCIPAL_ID string = managedIdentity.properties.principalId
output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = logAnalyticsWorkspace.name
output AZURE_LOG_ANALYTICS_WORKSPACE_ID string = logAnalyticsWorkspace.id
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.properties.loginServer
output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = managedIdentity.id
output AZURE_CONTAINER_REGISTRY_NAME string = containerRegistry.name
output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = containerAppEnvironment.name
output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = containerAppEnvironment.id
output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = containerAppEnvironment.properties.defaultDomain
output SERVICE_SERVER_VOLUME_GUITARDATA_NAME string = serverGuitarDataStore.name
output AZURE_VOLUMES_STORAGE_ACCOUNT string = storageVolume.name
</code></pre><p>In a real-world environment, you’ll need to update these to accommodate dependencies, networking and security rules, and so on.</p><p>Finally, we have the&nbsp;<em>main.parameters.json</em>&nbsp;file, which stores our, well, parameters.</p><pre><code class="language-bicep">.json{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "principalId": {
        "value": "${AZURE_PRINCIPAL_ID}"
      },
      "cache_password": {
        "value": "${AZURE_CACHE_PASSWORD}"
      },
      "password": {
        "value": "${AZURE_PASSWORD}"
      },
      "environmentName": {
        "value": "${AZURE_ENV_NAME}"
      },
      "location": {
        "value": "${AZURE_LOCATION}"
      }
    }
  }
</code></pre><p>So, why Bicep? Let’s talk about why Microsoft chose it for Aspire deployments.</p><p>For the uninitiated, Bicep is&nbsp;<a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep&ref=daveabrock.com">Azure’s domain-specific language (DSL) for deploying resources</a>. Think of it as a friendly wrapper around ARM (Azure Resource Manager) templates. Where ARM templates are verbose JSON documents, Bicep is concise, readable and suited for your Azure cloud deployments.</p><p>You might also be wondering: why not Terraform? For me, I view Terraform as the Switzerland of the infrastructure-as-code landscape: neutral, reliable and works everywhere.</p><p>Here’s why we’re opting for Bicep over Terraform:</p><ul><li><strong>Native Azure integration.</strong>&nbsp;Bicep has zero-day support for new Azure features—no waiting for provider updates.</li><li><strong>No state management.</strong>&nbsp;Bicep deployments are stateless; ARM is your state. No need to worry about state file corruption, backend configuration or state locks.</li><li><strong>Tighter IDE support.</strong>&nbsp;Visual Studio and VS Code give you IntelliSense for every Azure resource property.</li><li><strong>Azure-specific optimizations.</strong>&nbsp;Features like template specs and Azure blueprints only work with ARM/Bicep.</li></ul><p>Of course, Terraform is an IaC leader for a reason. It shines when you need multi-cloud deployments, a massive ecosystem, mature tooling and explicit state. For Aspire specifically, Bicep makes more sense. The&nbsp;<code>azd</code>&nbsp;CLI generates Bicep automatically from our AppHost, and the integration is seamless.</p><h2 id="other-considerations">Other Considerations</h2><p>Before we finish discussing our Aspire deployment to Azure Container Apps, I’d like to walk through some final considerations.</p><h3 id="service-to-service-communication-with-dapr">Service-to-Service Communication with Dapr</h3><p>One of Aspire’s biggest strengths is its embrace of Dapr. Without Dapr, service-to-service communication can be brittle—you hard-code hostnames, deal with manual retries and hope DNS resolves correctly.</p><p>With Dapr, services talk to each other using logical IDs. Dapr then handles retries, security and observability.</p><p>In our&nbsp;<code>AppHost</code>, we have:</p><pre><code class="language-csharp">var inventoryApi = builder.AddProject&lt;Projects.Api&gt;("inventoryapi")
    .WithReference(inventoryDb)
    .WithReference(cache);

var ordersApi = builder.AddProject&lt;Projects.OrdersApi&gt;("ordersapi")
    .WithReference(orderDb)
    .WithReference(inventoryApi);
</code></pre><p>When Orders API needs to call Inventory API, it doesn’t use&nbsp;<code>http://inventoryapi:8080</code>. Instead, it uses Dapr service invocation:</p><pre><code class="language-csharp">var response = await httpClient.GetAsync("http://inventoryapi/api/guitars");
</code></pre><p>Aspire’s service discovery wires this up automatically. In ACA, you enable Dapr in the Container App configuration, and it just works.</p><h3 id="managing-secrets-with-azure-key-vault">Managing Secrets with Azure Key Vault</h3><p>Secrets are where cloud deployments often get messy. Many times, developers hard-code them locally then scramble to hide them in production. In ACA, the best practice is to use Azure Key Vault to store your secrets.</p><p>Here’s a typical flow:</p><ol><li>Store secrets in Key Vault, like database passwords and API keys</li><li>Use managed identities so your ACA cotnainers can access Key Vault securely</li><li>Reference secrets in your container’s environment variables</li></ol><p>As we saw earlier in this series, our&nbsp;<code>AppHost</code>&nbsp;defines parameters:</p><pre><code class="language-csharp">var password = builder.AddParameter("password", secret: true);
var server = builder.AddSqlServer("server", password);
</code></pre><p>When we deploy with&nbsp;<code>azd</code>, we’re prompted for the password value and it gets stored in Key Vault automatically. Then, our Container Apps retrieve it at runtime using their managed identities. This way, we have no exposed passwords.</p><h3 id="observability-in-production">Observability in Production</h3><p>The Aspire dashboard is great locally. When you deploy to ACA, you get the dashboard in production too (as of Aspire 9.2 and later), but you’ll also want to leverage Azure’s native observability tools.</p><p>As we’ve learned, Azure emits telemetry using OpenTelemetry by default. Configure your exporters to send data to Azure:</p><ul><li><strong>Logs.</strong>&nbsp;Application Insights collects logs per service</li><li><strong>Metrics.</strong>&nbsp;Azure Monitor tracks CPU, memory and requests</li><li><strong>Traces.</strong>&nbsp;Distributed traces flow across services, letting us see request journeys end-to-end</li></ul><p>The caveat? Azure’s tools are powerful but can be overwhelming. Application Insights can generate mountains of logs and KQL takes learning. Costs grow with data volume.</p><p>The tradeoff here is Aspire giving you easy local observability, and ACA giving us scalable but more complex observability.</p><h3 id="scaling-and-cost-management">Scaling and Cost Management</h3><p>Scaling is ACA’s party trick: using&nbsp;<a href="https://keda.sh/?ref=daveabrock.com">Kubernetes Event-driven Autoscaling (KEDA) rules</a>, you can scale services up or down based on CPU, memory or even custom events. To save some coin, services can scale to zero when idle.</p><p>Scaling isn’t truly free, though. Cold starts mean your first request might take seconds. If your users expect instant responses, scaling to zero might frustrate them.</p><p>Costs can quickly add up because of:</p><ul><li>Log ingestion fees from Application Insights</li><li>Idle services that don’t quite scale to zero</li><li>Over-provisioning because of cold start concerns</li></ul><p>Start conservative, monitor and adjust. Aspire helps you design services to scale, but ACA billing enforces reality.</p><h2 id="honest-tradeoffs">Honest Tradeoffs</h2><p>Stepping back a bit, what’s the big picture?</p><p>With Aspire and ACA, we have an easy path from local development to cloud deployments, simple Dapr service discovery, strong Azure integration with its other resources, and serverless containers that can scale automatically.</p><p>It isn’t without drawbacks. We often experience cold starts and scaling quirks, debugging difficulties and no easy portability outside of Azure.</p><p>There is no free lunch. Aspire and ACA is excellent for Azure-first teams who want cloud-native deployments without the complexity of Kubernetes. If you need portability or fine-grained control, AKS might be a better choice.</p><h2 id="conclusion">Conclusion</h2><p>And with that, we’ve reached the end of our Aspire journey. We explored Aspire’s dashboard, defaults, integration and service discovery. Now we’ve seen how to take it all the way to production.</p><p>While the Aspire deployment story is still evolving, it shows you that it isn’t just for local development and can also be a framework to help you succeed in the cloud. And while ACA comes with tradeoffs, it gives you a fast, integrated way to run Aspire services at scale.</p><p>As with any technology, there is much more to explore. Check out&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview?ref=daveabrock.com">the Aspire docs</a>, start building and let me know how it goes. Happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 5: Orchestration and Service Discovery ]]></title>
        <description><![CDATA[ In Part 5, we introduce a brand-new Orders API, teach it to talk to Inventory and see how the Aspire orchestrator handles all the messy wiring for us. ]]></description>
        <link>https://www.daveabrock.com/2025/09/16/net-aspire-5-orchestration-and-service-discovery/</link>
        <guid isPermaLink="false">68f7c8fe353aec0001640eea</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 16 Sep 2025 12:57:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1602694251352-c8040a589547?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDF8fGNvbmR1Y3RvcnxlbnwwfHx8fDE3NjEwNjk2NjZ8MA&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published on the <a href="https://www.telerik.com/blogs/net-aspire-5-orchestration-service-discovery?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p><em>This is Part 5 of our six‑part deep dive into .NET Aspire.</em></p><ul><li>Part 1:&nbsp;What is .NET Aspire?</li><li>Part 2:&nbsp;Exploring the Developer Dashboard</li><li>Part 3:&nbsp;Service Defaults</li><li>Part 4:&nbsp;Integrations</li><li><strong>This post (Part 5)</strong>: Orchestration &amp; Service Discovery</li><li>Part 6: Deployment Using Azure Container Apps</li></ul><p>Welcome back, friends. We’re really cooking with gas now.</p><p>Up to this point, we’ve:</p><ul><li>Said “hello, world” to .NET Aspire and learned why an application model beats a folder full of ad-hoc Docker Compose files</li><li>Poked around the Developer Dashboard to watch our app light up in real-time</li><li>Saw how Service Defaults added opinionated capabilities like OpenTelemetry, health probes and resilience across every service with one line of code</li><li>Plugged SQL Server and Redis into the mix</li></ul><p>We’ve had a lot of fun so far, but up to this point we’ve been hosting a party of one: an Inventory API that lists guitars for sale. Today, we’ll introduce a brand-new Orders API, teach it how to talk to Inventory, and see how the Aspire orchestrator handles all the messy wiring for us.</p><p><strong>Note</strong>: This series focuses on .NET Aspire and not writing APIs, so I’ll be assuming you have general working knowledge of how to write C# APIs. I will explain new code where relevant.</p><h2 id="why-orchestration-matters">Why Orchestration Matters</h2><p>Why does orchestration matter? Docker Compose and Kubernetes absolutely help with scheduling containers, but they live outside of your codebase. Your CI pipeline has to juggle a bunch of YAML files, keep ports in sync and pray nobody commits a hard‑coded endpoint by mistake.</p><p>With Aspire, orchestration moves back into C#. You declare what exists and how pieces relate.</p><ul><li><strong>Lifecycle</strong>: Databases come online before the APIs that depend on them.</li><li><strong>Configuration</strong>: Connection strings, secrets and URLs flow in through environment variables.</li><li><strong>Resilience and telemetry</strong>: Opt in once with&nbsp;<code>AddServiceDefaults()</code>&nbsp;and every outbound call is wrapped with retries, time‑outs and OpenTelemetry spans.</li></ul><p>In short, with Aspire orchestration is the central hub that knows the dependency graph, watches health probes and keeps secrets safe. No more depending on a dated&nbsp;<code>README.md</code>&nbsp;and launching nine terminals.</p><h2 id="revisiting-service-defaults">Revisiting Service Defaults</h2><p>Before we start wiring up new services, let’s revisit service defaults. In our previous post, we saw how a single call to&nbsp;<code>builder.AddServiceDefaults()</code>&nbsp;adds OpenTelemetry instrumentation, health probes, service discovery and a resilience pipeline. Those defaults apply to every ASP.NET Core project that opts in by calling&nbsp;<code>builder.AddServiceDefaults()</code>.</p><p>This allows service defaults to do the heavy lifting for orchestration. When the AppHost injects environment variables like&nbsp;<code>ConnectionStrings__guitardb</code>, our services automatically pick them up through configuration binding. Telemetry flows to the dashboard without any extra code. And when we call another service via&nbsp;<code>HttpClient</code>, the standard resilience handler adds retries, timeouts and circuit breakers.</p><p>We won’t rehash all of the implementation details here—see&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-3-service-defaults?ref=daveabrock.com">Part 3</a>&nbsp;for in-depth details. However, keep in mind that everything we build in this post rests on these conventions.</p><h2 id="meet-the-orders-api">Meet the Orders API</h2><p>Our guitar shop currently consists of a Blazor frontend and a single Inventory (<code>/guitars</code>) API that handles basic create-read-update-delete (CRUD) operations. We’ll now introduce an Orders API.</p><p>The Orders API will:</p><ol><li>Accept an order from our Blazor app</li><li>For each line item, ask the Inventory API whether the product exists and has stock</li><li>If validation passes, calculate tax, persist the order and reply&nbsp;<code>201 Created</code>&nbsp;with an order summary</li></ol><p><strong>Note</strong>: For clarity and conciseness, the following code is under a single endpoint. For a “real-world” production app, much of this logic will live in other parts of your application.</p><h3 id="build-the-endpoint">Build the Endpoint</h3><p>Let’s create the Orders API. Let’s take a look at our&nbsp;<code>POST</code>&nbsp;endpoint. I’ll walk you through it next.</p><pre><code class="language-csharp">app.MapPost("/orders", async (CreateOrderRequest req,
                              OrdersDbContext db,
                              InventoryClient inventory) =&gt;
{
    if (!req.Lines.Any())
        return Results.BadRequest("At least one line is required.");

    var validatedLines = new List&lt;OrderLine&gt;();
    foreach (var line in req.Lines)
    {
        var product = await inventory.GetAsync(line.ProductId);
        if (product is null) return Results.BadRequest($"Product {line.ProductId} not found");
        if (product.Stock &lt; line.Quantity) return Results.BadRequest($"Insufficient stock for {product.Sku}");

        validatedLines.Add(new OrderLine
        {
            ProductId  = line.ProductId,
            Quantity   = line.Quantity,
            UnitPrice  = product.Price
        });
    }

    var subtotal = validatedLines.Sum(l =&gt; l.LineTotal);
    var tax = Math.Round(subtotal * 0.05m, 2);

    var order = new Order
    {
        CustomerName = req.CustomerName,
        Subtotal     = subtotal,
        Tax          = tax,
        Lines        = validatedLines
    };

    db.Orders.Add(order);
    await db.SaveChangesAsync();

    return Results.Created($"/orders/{order.Id}",
        new { order.Id, order.OrderNumber, order.Subtotal, order.Tax, order.Total });
});
</code></pre><p>What just happened?</p><ol><li>We use a guard clause to reject an empty order.</li><li>We use cross-service validation to check inventory, so we don’t just assume a product is in stock.</li><li>We calculate tax.</li><li>We use Entity Framework Core to write the order to a&nbsp;<code>OrdersDb</code>&nbsp;database.</li><li>And we respond with a&nbsp;<code>201 Created</code>&nbsp;with the new resource.</li></ol><h3 id="how-does-orders-talk-to-inventory">How Does Orders Talk to Inventory?</h3><p>In our new API’s&nbsp;<code>Program.cs</code>, we register an HTTP client:</p><pre><code class="language-csharp">builder.Services.AddHttpClient&lt;InventoryClient&gt;(client =&gt;
    client.BaseAddress = new Uri("https+http://inventory"));
</code></pre><p>The URI looks a little funky: notice the scheme (<code>https+http</code>) and the host (<code>inventory</code>).</p><ul><li><code>https+http</code>&nbsp;tells Aspire’s resolver to try HTTPS first, then fall back to HTTP.</li><li>As you likely noticed,&nbsp;<code>inventory</code>&nbsp;isn’t a DNS name. It’s the canonical service name we’ll define in the&nbsp;<code>AppHost</code>.</li></ul><p>If you remember, we defined it earlier:</p><pre><code class="language-csharp">var inventoryApi = builder.AddProject&lt;Projects.Api&gt;("inventory")
    .WithReference(inventoryDb)
    .WithReference(cache)
    .WaitFor(inventoryDb);
</code></pre><p>With this in place, Aspire injects the actual URL via configuration. As a result, we don’t require port numbers, a localhost or environment‑specific configuration. At runtime, Aspire injects two environment variables:</p><pre><code>Services__inventory__https = https://localhost:6001
Services__inventory__http  = http://localhost:5001
</code></pre><p>The resolver swaps the placeholder URI for the real endpoint. Just like that, service discovery handles it all.</p><h2 id="upgrade-the-blazor-frontend">Upgrade the Blazor Frontend</h2><p>Our new service isn’t helpful if our customers can’t see it. Let’s now walk through the three components that showcase the Orders API.</p><p>Each component uses typed&nbsp;<code>HttpClient</code>&nbsp;services so they inherit telemetry, resilience and service discovery out of the box.</p><pre><code class="language-csharp">builder.Services.AddHttpClient&lt;OrdersHttpClient&gt;(client =&gt;
    client.BaseAddress = new Uri("https+http://orders"))
        .AddServiceDiscovery()           
        .AddStandardResilienceHandler();
</code></pre><h3 id="order-list-page">Order List Page</h3><p>For an order list, we’re using a paginated grid that lets you click a row for details. It also supports inline deletes without a page refresh.</p><pre><code class="language-csharp">@page "/orders"
@inject OrdersHttpClient Http
@inject NavigationManager Nav
@inject IJSRuntime JS

&lt;PageTitle&gt;Orders&lt;/PageTitle&gt;
&lt;div class="container py-4"&gt;
    &lt;div class="d-flex justify-content-between align-items-center mb-3"&gt;
        &lt;h1 class="display-6 d-flex gap-2 mb-0"&gt;
            &lt;span&gt;🧾&lt;/span&gt; Orders
        &lt;/h1&gt;
        &lt;button class="btn btn-primary" @onclick="CreateNewOrder"&gt;
            ➕ New Order
        &lt;/button&gt;
    &lt;/div&gt;

    @if (_orders is null)
    {
        &lt;p&gt;Loading…&lt;/p&gt;
    }
    else
    {
        &lt;table class="table table-striped"&gt;
            &lt;thead class="table-light small text-uppercase"&gt;
                &lt;tr&gt;
                    &lt;th&gt;#&lt;/th&gt;
                    &lt;th&gt;Date&lt;/th&gt;
                    &lt;th&gt;Customer Name&lt;/th&gt;
                    &lt;th&gt;Total&lt;/th&gt;
                    &lt;th&gt;Delete?&lt;/th&gt;
                &lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;
                @foreach (var o in _orders)
                {
                    &lt;tr style="cursor:pointer"
                        @onclick="@(() =&gt; Nav.NavigateTo($"/orders/{o.Id}"))"&gt;
                        &lt;td&gt;@o.OrderNumber&lt;/td&gt;
                        &lt;td&gt;@o.CreatedUtc.ToString("yyyy-MM-dd")&lt;/td&gt;
                        &lt;td&gt;@o.CustomerName&lt;/td&gt;
                        &lt;td&gt;@o.Total.ToString("C")&lt;/td&gt;
                        &lt;td&gt;
                            &lt;button class="btn btn-sm btn-link text-danger"
                                    title="Delete"
                                    @onclick:stopPropagation
                                    @onclick="() =&gt; DeleteOrder(o.Id)"&gt;
                                🗑
                            &lt;/button&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                }
            &lt;/tbody&gt;
        &lt;/table&gt;
    }
&lt;/div&gt;

@code {
    private List&lt;OrderSummaryDto&gt;? _orders;

    protected override async Task OnInitializedAsync()
        =&gt; _orders = (await Http.GetOrdersAsync()).ToList();

    async Task DeleteOrder(Guid id)
    {
        bool ok = await JS.InvokeAsync&lt;bool&gt;("confirm", "Delete this order?");
        if (!ok) return;

        var resp = await Http.DeleteOrderAsync(id);
        if (resp.IsSuccessStatusCode)
        {
            var row = _orders.FirstOrDefault(x =&gt; x.Id == id);
            if (row is not null)
            {
                _orders.Remove(row);    
                StateHasChanged();      
            }
        }
        else
        {
            await JS.InvokeVoidAsync("alert", $"Delete failed – {resp.StatusCode}");
        }
    }

    private void CreateNewOrder() =&gt; Nav.NavigateTo("/create-order");
}
</code></pre><p>Here’s the finished Order List page.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/orderlist.png?sfvrsn=e1a8dc02_2" class="kg-image" alt="orderlist" loading="lazy" width="738" height="782"></figure><h3 id="order-details-page">Order Details Page</h3><p>With the Order List page set, we can build an Order Details page. This page displays the full invoice with the line-item pricing pulled directly from the server.</p><pre><code class="language-csharp">@page "/orders/{Id:guid}"
@inject OrdersHttpClient Http

&lt;h1 class="mb-3"&gt;Order @Id&lt;/h1&gt;

@if (_order is null)
{
    &lt;p&gt;Loading…&lt;/p&gt;
}
else
{
    &lt;p&gt;&lt;b&gt;Customer:&lt;/b&gt; @_order.CustomerName&lt;/p&gt;
    &lt;p&gt;&lt;b&gt;Date:&lt;/b&gt; @_order.CreatedUtc.ToString("u")&lt;/p&gt;

    &lt;table class="table"&gt;
        &lt;thead&gt;
            &lt;tr&gt;
                &lt;th&gt;Product&lt;/th&gt;
                &lt;th class="text-end"&gt;Qty&lt;/th&gt;
                &lt;th class="text-end"&gt;Line Total&lt;/th&gt;
            &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
            @foreach (var l in _order!.Lines)
            {
                &lt;tr&gt;
                    &lt;td&gt;@l.ProductName&lt;/td&gt;
                    &lt;td class="text-end"&gt;@l.Quantity&lt;/td&gt;
                    &lt;td class="text-end"&gt;@l.LineTotal.ToString("C")&lt;/td&gt;
                &lt;/tr&gt;
            }
        &lt;/tbody&gt;
        &lt;tfoot&gt;
            &lt;tr&gt;&lt;td colspan="2" class="text-end"&gt;Subtotal&lt;/td&gt;&lt;td class="text-end"&gt;@_order.Subtotal.ToString("C")&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td colspan="2" class="text-end"&gt;Tax&lt;/td&gt;&lt;td class="text-end"&gt;@_order.Tax.ToString("C")&lt;/td&gt;&lt;/tr&gt;
            &lt;tr class="fw-bold"&gt;&lt;td colspan="2" class="text-end"&gt;Total&lt;/td&gt;&lt;td class="text-end"&gt;@_order.Total.ToString("C")&lt;/td&gt;&lt;/tr&gt;
        &lt;/tfoot&gt;
    &lt;/table&gt;
}

@code {
    [Parameter] public Guid Id { get; set; }
    private OrderDetailDto? _order;

    protected override async Task OnParametersSetAsync()
        =&gt; _order = await Http.GetOrderAsync(Id);
}
</code></pre><p>We can then easily view a breakdown of an order:</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/orderdetails.png?sfvrsn=1310d955_2" class="kg-image" alt="orderdetails" loading="lazy" width="1023" height="429"></figure><h3 id="create-order-page">Create Order Page</h3><p>We also built a friendly form that queries the Inventory API for the guitar catalog, lets the user order multiple line items and then calculates the totals client-side.</p><pre><code class="language-csharp">@page "/create-order"
@using Entities
@inject InventoryHttpClient Inventory
@inject OrdersHttpClient    Orders
@inject NavigationManager   Nav
@inject IJSRuntime          JS

&lt;PageTitle&gt;Create Order&lt;/PageTitle&gt;

@if (_guitars is null)
{
    &lt;p class="m-4"&gt;Loading catalog…&lt;/p&gt;
    return;
}

&lt;div class="container py-4" style="max-width:720px"&gt;
    &lt;h1 class="display-6 mb-4"&gt;➕ Create Order&lt;/h1&gt;
    &lt;div class="mb-3"&gt;
        &lt;label class="form-label fw-semibold"&gt;Customer name&lt;/label&gt;
        &lt;InputText @bind-Value="_customerName" class="form-control" /&gt;
    &lt;/div&gt;
    &lt;EditForm Model="_draft" OnValidSubmit="AddLine"&gt;
        &lt;div class="row g-2 align-items-end"&gt;
            &lt;div class="col-7"&gt;
                &lt;label class="form-label"&gt;Product&lt;/label&gt;
                &lt;InputSelect TValue="Guid?" @bind-Value="_draft.ProductId" class="form-select"&gt;
                    &lt;option value=""&gt;‒ select guitar ‒&lt;/option&gt;
                    @foreach (var g in _guitars)
                    {
                        &lt;option value="@g.Id"&gt;
                            @($"{g.Brand} {g.Model} — {g.Price:C}")
                        &lt;/option&gt;
                    }
                &lt;/InputSelect&gt;
            &lt;/div&gt;
            &lt;div class="col-2"&gt;
                &lt;label class="form-label"&gt;Qty&lt;/label&gt;
                &lt;InputNumber @bind-Value="_draft.Quantity" class="form-control" min="1" max="10" /&gt;
            &lt;/div&gt;
            &lt;div class="col-3 text-end"&gt;
                &lt;label class="form-label invisible"&gt;btn&lt;/label&gt;
                &lt;button class="btn btn-outline-primary w-100" disabled="@(!_draft.IsValid)"&gt;
                    Add
                &lt;/button&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/EditForm&gt;

    @if (_lines.Any())
    {
        &lt;table class="table table-sm table-hover my-4"&gt;
            &lt;thead class="table-light small text-uppercase"&gt;
                &lt;tr&gt;
                    &lt;th&gt;Product&lt;/th&gt;
                    &lt;th class="text-end"&gt;Qty&lt;/th&gt;
                    &lt;th class="text-end"&gt;Line&amp;nbsp;Total&lt;/th&gt;
                    &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;
                @foreach (var l in _lines)
                {
                    var g = _guitarsById[l.ProductId];
                    &lt;tr&gt;
                        &lt;td&gt;@g.Brand @g.Model&lt;/td&gt;
                        &lt;td class="text-end"&gt;@l.Quantity&lt;/td&gt;
                        &lt;td class="text-end"&gt;@((g.Price * l.Quantity).ToString("C"))&lt;/td&gt;
                        &lt;td class="text-end"&gt;
                            &lt;button class="btn btn-sm btn-link text-danger"
                                    @onclick="() =&gt; RemoveLine(l)"&gt;
                                ✖
                            &lt;/button&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                }
            &lt;/tbody&gt;
        &lt;/table&gt;
        &lt;div class="text-end mb-3"&gt;
            &lt;div&gt;Subtotal: &lt;strong&gt;@_subtotal.ToString("C")&lt;/strong&gt;&lt;/div&gt;
            &lt;div&gt;Tax (5 %): &lt;strong&gt;@_tax.ToString("C")&lt;/strong&gt;&lt;/div&gt;
            &lt;div class="fs-5"&gt;Total: &lt;strong&gt;@_total.ToString("C")&lt;/strong&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;button class="btn btn-success" @onclick="SubmitOrder"&gt;Submit Order&lt;/button&gt;
    }
&lt;/div&gt;

@code {
    private IReadOnlyList&lt;GuitarDto&gt;? _guitars;
    private Dictionary&lt;Guid, GuitarDto&gt; _guitarsById = new();
    private readonly List&lt;CreateOrderLine&gt; _lines = [];
    private readonly LineDraft _draft = new();
    private string _customerName = "Web Customer";

    private decimal _subtotal, _tax, _total;

    protected override async Task OnInitializedAsync()
    {
        _guitars = await Inventory.GetGuitarsAsync();
        _guitarsById = _guitars.ToDictionary(g =&gt; g.Id);
    }

    void AddLine()
    {
        if (!_draft.IsValid) return;

        _lines.Add(new CreateOrderLine(_draft.ProductId!.Value, _draft.Quantity));
        _draft.Reset();
        RecalcTotals();
    }

    void RemoveLine(CreateOrderLine l)
    {
        _lines.Remove(l);
        RecalcTotals();
    }

    void RecalcTotals()
    {
        _subtotal = _lines.Sum(l =&gt; _guitarsById[l.ProductId].Price * l.Quantity);
        _tax      = Math.Round(_subtotal * 0.05m, 2);
        _total    = _subtotal + _tax;
    }

    async Task SubmitOrder()
    {
        var req  = new CreateOrderRequest(_customerName, _lines);
        var resp = await Orders.SubmitOrderAsync(req);

        if (resp.IsSuccessStatusCode)
            Nav.NavigateTo("/orders");
        else
            await JS.InvokeVoidAsync("alert", $"Order failed – {resp.StatusCode}");
    }

    private class LineDraft
    {
        public Guid? ProductId { get; set; }
        public int   Quantity  { get; set; } = 1;

        public bool IsValid =&gt; ProductId.HasValue &amp;&amp; Quantity &gt; 0;

        public void Reset()
        {
            ProductId = null;
            Quantity  = 1;
        }
    }
}
</code></pre><p>Here’s our new Create Order page.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/createorder.png?sfvrsn=d067f62c_2" class="kg-image" alt="createorder" loading="lazy" width="801" height="528"></figure><p>With these three Razor components in place, the UI now consumes the full Orders API—and, transitively, the Inventory API—all without hard-coding a single URL.</p><h2 id="checking-in-on-the-apphost">Checking In on the AppHost</h2><p>With our new service in place, let’s orchestrate them. Let’s look at the final&nbsp;<code>Program.cs</code>&nbsp;for the AppHost project:</p><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var password = builder.AddParameter("password", secret: true);
var server = builder.AddSqlServer("server", password, 1433)
        .WithDataVolume("guitar-data")
        .WithLifetime(ContainerLifetime.Persistent);

var inventoryDb = server.AddDatabase("guitardb");
var orderDb = server.AddDatabase("ordersdb");

var cache = builder.AddRedis("cache")
            .WithRedisInsight()
            .WithLifetime(ContainerLifetime.Persistent);

var inventoryApi = builder.AddProject&lt;Projects.Api&gt;("inventory")
    .WithReference(inventoryDb)
    .WithReference(cache)
    .WaitFor(inventoryDb);

var ordersApi = builder.AddProject&lt;Projects.OrdersApi&gt;("orders")
        .WithReference(orderDb)
        .WithReference(inventoryApi)
        .WaitFor(orderDb);  

builder.AddProject&lt;Projects.Frontend&gt;("frontend")
    .WithReference(inventoryApi)
    .WithReference(ordersApi)
    .WaitFor(inventoryApi)
    .WaitFor(ordersApi)
    .WithExternalHttpEndpoints();

builder.Build().Run();
</code></pre><p>When you run the project through&nbsp;<code>AppHost</code>, the orchestrator spins up SQL Server, the Inventory API and the Orders API—all in the correct order.</p><p>Each project receives environment variables pointing at its dependencies. Because we called&nbsp;<code>AddServiceDefaults</code>&nbsp;in both our APIs, they automatically read these variables.</p><p>For example, the inventory service reads&nbsp;<code>ConnectionStrings__guitardb</code>&nbsp;to configure EF Core, and the orders service reads&nbsp;<code>Services__inventory__https</code>&nbsp;to configure its HTTP client.</p><p>With multiple services, the built-in health endpoints are even more important. Our&nbsp;<code>AppHost</code>&nbsp;uses these endpoints to decide when a service is ready. If the inventory service fails its health probe, the orders service waits until it is healthy. If a downstream call repeatedly fails, the circuit breaker configured by&nbsp;<code>AddServiceDefaults</code>&nbsp;prevents overwhelming the dependency.</p><h2 id="observing-the-end%E2%80%91to%E2%80%91end-flow">Observing the End‑to‑end Flow</h2><p>Let’s fire up our full solution and observe what happens. From the terminal, run:</p><pre><code class="language-bash">dotnet run --project GuitarShop.AppHost
</code></pre><p>Aspire builds each project, creates a SQL Server container, launches the inventory and orders services, and opens the Developer Dashboard. On the&nbsp;<strong>Resources</strong>&nbsp;page you’ll see what we’ve built so far.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/resource-graph.png?sfvrsn=66664c5c_2" class="kg-image" alt="resource graph" loading="lazy" width="797" height="793"></figure><p>Clicking on&nbsp;<code>orders</code>&nbsp;reveals its environment variables—notice the&nbsp;<code>Services__inventory</code>&nbsp;entry pointing to the actual endpoints.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/inventory.png?sfvrsn=45ed2c3d_2" class="kg-image" alt="inventory" loading="lazy" width="628" height="87"></figure><p>Let’s place an order from the frontend. Open the&nbsp;<strong>Traces</strong>&nbsp;tab and you’ll see a span for the incoming POST&nbsp;<code>/orders</code>&nbsp;request, a child span for the outgoing GET&nbsp;<code>/guitars/{id}</code>&nbsp;call to inventory. This confirms that our instrumentation is working—the entire chain is captured and visualized.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/entire-chain.png?sfvrsn=343a4ed2_2" class="kg-image" alt="entire chain" loading="lazy" width="1323" height="343"></figure><h2 id="wrapping-up-and-what%E2%80%99s-next">Wrapping Up (And What’s Next)</h2><p>In this post, things got real: we added our first real orchestration scenario to Dave’s Guitar Shop. We built a new orders service alongside our existing inventory service, used Aspire’s service defaults to add telemetry and resilience, and orchestrated everything through the AppHost. The AppHost now declares separate databases for inventory and orders, and injects connection strings into the services.</p><p>In the final part of this series, we’ll take our project of our laptops and to the cloud. We’ll see how Aspire’s Azure Container Apps integration maps our SQL and Redis resources to Azure offerings and how the same AppHost definition can be used to deploy our entire guitar shop with a single&nbsp;<code>az containerapp up</code>&nbsp;command.</p><p>Stay tuned and see you soon!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 4: Integrations ]]></title>
        <description><![CDATA[ This post was originally published in the Telerik Developer Blog.

This is the fourth part of a six-part exploratory series on .NET Aspire.

 * Part 1: What is .NET Aspire?
 * Part 2: Exploring the Developer Dashboard
 * Part 3: Service Defaults
 * This post (Part 4): Integrations
 * Part 5: Orchestration and Service Discovery ]]></description>
        <link>https://www.daveabrock.com/2025/08/28/net-aspire-4-integrations/</link>
        <guid isPermaLink="false">68f7c81c353aec0001640ecf</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Thu, 28 Aug 2025 12:54:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1662116137244-b7c6fdc1ac35?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDE0fHxwcm9ncmFtbWVyfGVufDB8fHx8MTc2MTA2ODk4MXww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published in the <a href="https://www.telerik.com/blogs/net-aspire-4-integrations?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog.</a></blockquote><p><em>This is the fourth part of a six-part exploratory series on .NET Aspire.</em></p><ul><li>Part 1:&nbsp;What is .NET Aspire?</li><li>Part 2:&nbsp;Exploring the Developer Dashboard</li><li>Part 3:&nbsp;Service Defaults</li><li><strong>This post (Part 4): Integrations</strong></li><li>Part 5:&nbsp;Orchestration and Service Discovery</li><li>Part 6: Deployment using Azure Container Apps</li></ul><p>Hello again, friends.</p><p>In the first three installments of this .NET Aspire series, we did the following:</p><ul><li>Said&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-1-what-is-net-aspire?ref=daveabrock.com">hi to .NET Aspire</a>&nbsp;and saw how its opinionated approach removes a ton of cloud-native pain.</li><li>Fired up&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-2-developer-dashboard?ref=daveabrock.com">the Developer Dashboard</a>&nbsp;to watch traces, logs and metrics without juggling terminal windows.</li><li>Met&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-4-integrations?ref=daveabrock.com">Service Defaults</a>&nbsp;and learned how a single extension method sprinkles telemetry, health checks and resilience across every project.</li></ul><p>Today we’ll turn infrastructure into C# code. We’ll grab my hacked-together SQL Server container out of Docker Compose, drop it into Aspire and speed up reads with a Redis cache. Both resources spin up, wire up and light up in the dashboard. No port-mapping gymnastics required.</p><p>Enough talk! Bring on the code.</p><h2 id="add-a-containerized-sql-server-to-net-aspire">Add a Containerized SQL Server to .NET Aspire</h2><p>My SQL Server container works in Docker Compose but it’s a second-class citizen. By inviting it to Aspire, we get:</p><ul><li><strong>A shared toolchain</strong>: We use one&nbsp;<code>AppHost</code>, one launch profile and one CI pipeline.</li><li><strong>No extra&nbsp;<code>docker compose up</code>&nbsp;step</strong>: Hit F5 (or&nbsp;<code>dotnet run</code>) and SQL starts with everything else.</li><li><strong>Automatic health probes, discovery and secrets</strong>: Service Defaults injects connection strings and OTLP endpoints for us.</li><li><strong>Native observability</strong>: Logs, traces and metrics flow straight to the developer dashboard.</li></ul><h3 id="add-sql-server-as-an-aspire-resource">Add SQL Server as an Aspire Resource</h3><p>To get this party started, let’s navigate to our&nbsp;<code>AppHost</code>&nbsp;project and update&nbsp;<code>Program.cs</code>. After you review the code, we’ll walk through it in detail.</p><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var password = builder.AddParameter("password", secret: true);
var server = builder.AddSqlServer("server", password, 1433)
        .WithDataVolume("guitar-data")
        .WithLifetime(ContainerLifetime.Persistent);

var db = server.AddDatabase("guitardb");

var api = builder.AddProject&lt;Projects.Api&gt;("api")
    .WithReference(db)
    .WaitFor(db);

// The following code is the same as before
builder.AddProject&lt;Projects.Frontend&gt;("frontend")
    .WithReference(api)
    .WaitFor(api)
    .WithExternalHttpEndpoints();

builder.Build().Run();
</code></pre><h4 id="securely-capture-secrets">Securely Capture Secrets</h4><p>In this example:</p><pre><code class="language-csharp">var password = builder.AddParameter("password", secret: true);
</code></pre><p><code>AddParameter</code>&nbsp;creates a parameter resource. When we set the&nbsp;<code>secret</code>&nbsp;parameter to&nbsp;<code>true</code>, we tell Aspire to treat the value like a secret and makes it easy to override with an environment variable or user secrets during local development.</p><p>In our&nbsp;<code>secrets.json</code>&nbsp;(or&nbsp;<code>appsettings.json</code>), I read it in using the following structure:</p><pre><code class="language-json">{
  "Parameters": {
    "password": "Dave#123"
  }
}
</code></pre><p>Obviously,&nbsp;<strong>this is only suitable for local development</strong>. When deploying to servers, you’ll want a better security model like Azure Key Vault. In that case, you can update your code to the following:</p><pre><code class="language-csharp">var keyVault = builder.AddAzureKeyVault("key‑vault");
builder.Configuration.AddAzureKeyVaultSecrets("key‑vault");   

var sqlPassword = builder.AddParameter("sql-password", secret: true);
</code></pre><h4 id="spin-up-a-sql-server-with-storage">Spin Up a SQL Server with Storage</h4><p>For this example:</p><pre><code class="language-csharp">var server = builder.AddSqlServer("server", password, 1433)
        .WithDataVolume("guitar-data")
        .WithLifetime(ContainerLifetime.Persistent);
</code></pre><p>What just happened?</p><ul><li><code>AddSqlServer</code>&nbsp;pulls the official&nbsp;<code>mcr.microsoft.com/mssql/server:2022-latest</code>&nbsp;image, sets&nbsp;<code>SA_PASSWORD</code>&nbsp;to our password, and maps it to port 1433.</li><li><code>WithDataVolume("guitar-data")</code>&nbsp;mounts a named Docker volume so our container survives rebuilds.</li><li>Finally,&nbsp;<code>WithLifetime(ContainerLifetime.Persistent)</code>&nbsp;tells Aspire to reuse the same instance between runs. This avoids slow startup times and having to run migrations every time.</li></ul><h4 id="adding-the-database">Adding the Database</h4><p>This one-liner …</p><pre><code class="language-csharp">var db = server.AddDatabase("guitardb");
</code></pre><p>… is syntactic sugar for writing a&nbsp;<code>CREATE DATABASE guitardb</code>&nbsp;command when we first launch, and also generates a strongly typed connection string resource. That connection string can now be referenced by any project that needs it.</p><p>We’ve added the database, but it’s empty and we need to seed it. Starting with Aspire 9.2, you can use the&nbsp;<code>WithCreationScript</code>&nbsp;method.</p><p>With a script (or set of scripts) in hand, make sure you’re copying it to the&nbsp;<code>AppHost</code>&nbsp;output directory by adding this to your project file:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
  &lt;None Include="..\Api\data\createdb.sql" Link="createdb.sql"&gt;
    &lt;CopyToOutputDirectory&gt;PreserveNewest&lt;/CopyToOutputDirectory&gt;
  &lt;/None&gt;
&lt;/ItemGroup&gt;
</code></pre><p>We can now update the AppHost’s&nbsp;<code>Program.cs</code>&nbsp;database code to the following.</p><pre><code class="language-csharp">var password = builder.AddParameter("password", secret: true);
var server = builder.AddSqlServer("server", password, 1433)
        .WithDataVolume("guitar-data")
        .WithLifetime(ContainerLifetime.Persistent);

var scriptPath = Path.Join(Path.GetDirectoryName(typeof(Program).Assembly.Location), "createdb.sql");
var db = server.AddDatabase("guitardb").WithCreationScript(File.ReadAllText(scriptPath));
</code></pre><p>This is just one of many ways you can see data. To learn more,&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/database/seed-database-data?tabs=sql-server&ref=daveabrock.com">read the Microsoft Docs</a>.</p><h4 id="register-the-api-with-the-database">Register the API with the Database</h4><p>Finally, this code registers the API to the database.</p><pre><code class="language-csharp">var api = builder.AddProject&lt;Projects.Api&gt;("api")
    .WithReference(db)
    .WaitFor(db);
</code></pre><p>The&nbsp;<code>WithReference(db)</code>&nbsp;injects two things into the container:</p><ul><li>The connection string as&nbsp;<code>ConnectionStrings__guitardb</code></li><li>The health-probe address for the SQL container so your app knows when the database is up</li></ul><p>The&nbsp;<code>WaitFor(db)</code>&nbsp;line means Aspire won’t even&nbsp;<code>docker run</code>&nbsp;the API until SQL Server reports it as healthy.</p><h3 id="update-the-inventory-api">Update the Inventory API</h3><p>Because we already rely on Service Defaults, the API can pick up&nbsp;<code>builder.Configuration.GetConnectionString("db")</code>&nbsp;automatically. The only code we need to touch is making sure EF Core is registered to use the database in the API project’s&nbsp;<code>Program.cs</code>:</p><pre><code class="language-csharp">builder.Services.AddSqlServer&lt;GuitarStoreContext&gt;("guitardb");
</code></pre><p>That single line allows the&nbsp;<code>AppHost</code>&nbsp;project to spin up the SQL Server container and inject its connection string into the API at launch. Service Defaults then wires up logging, tracing, metrics and resilience. As a result, the&nbsp;<code>AddSqlServer&lt;GuitarStoreContext&gt;("guitardb")</code>&nbsp;call grabs the injected connection string, registers the&nbsp;<code>DbContext</code>&nbsp;and plugs into our observability out of the box.</p><h3 id="examine-the-dashboard">Examine the Dashboard</h3><p>When we fire up the app, we now see the database up and running alongside our app.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/dashboard-with-sql.png?sfvrsn=aa800aae_2" class="kg-image" alt="dashboard with sql" loading="lazy" width="1197" height="426"></figure><p>If we review the details of the API resource, we see the injected connection string, too.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/db-env-variable.png?sfvrsn=cc8e82bd_2" class="kg-image" alt="db env variable" loading="lazy" width="484" height="265"></figure><p>Our telemetry lights up: if we browse to our traces, we can see a request end-to-end.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/db-trace.png?sfvrsn=d030341e_2" class="kg-image" alt="db trace" loading="lazy" width="1038" height="335"></figure><p>Our database is officially out of Docker Compose and into Aspire! We can now delete the old&nbsp;<code>docker-compose.yml</code>&nbsp;and use SQL Server alongside the rest of our project with a single F5 command (or&nbsp;<code>dotnet run</code>).</p><p>We can now move onto our Redis integration to speed up our reads.</p><h2 id="adding-redis-for-lightning-fast-caching">Adding Redis for Lightning-fast Caching</h2><p>Our&nbsp;<code>/guitars</code>&nbsp;endpoint is read-heavy. To make it lightning-fast (and to avoid round-trips to the database), we’ll add Redis as a cache layer and let Aspire wire things up.</p><p>To wire Redis in&nbsp;<code>AppHost</code>, we’ll add this right after the SQL snippet.</p><pre><code class="language-csharp">var cache = builder.AddRedis("cache")
                   .WithRedisInsight()
                   .WithLifetime(ContainerLifetime.Persistent);
</code></pre><p>What happens here? We pull a Redis container from&nbsp;<code>docker.io/library/redis</code>&nbsp;that helps to avoid any local installs or port wrangling. We also get a&nbsp;<code>PING</code>&nbsp;health probe that is viewable from the&nbsp;<code>/health</code>&nbsp;endpoint and the developer dashboard.</p><p>Then, the connection string&nbsp;<code>ConnectionStrings:cache</code>&nbsp;gets injected automatically into any project that calls&nbsp;<code>WithReference(cache)</code>.</p><p>Optionally, we can also include our favorite Redis admin UI, as Aspire supports&nbsp;<a href="https://redis.io/insight/?ref=daveabrock.com">Redis Insight</a>&nbsp;or&nbsp;<a href="https://joeferner.github.io/redis-commander/?ref=daveabrock.com">Redis Commander</a>. I’ve added Redis Insight. When I do so, Aspire grabs&nbsp;<code>docker.io/redis/redisinsight</code>&nbsp;to allow me to easily work with my Redis instance.</p><p>Much like with our SQL Server container, we add&nbsp;<code>.WithLifetime(ContainerLifetime.Persistent)</code>&nbsp;to tell Aspire, “Don’t tear down the container when I stop debugging.” The result is much faster start-ups and durable state between sessions—great for day-to-day development, demos or long-running background jobs. If you ever need a clean slate, you can still prune the container manually or switch the lifetime back to the default&nbsp;<code>ContainerLifetime.Transient</code>&nbsp;mode.</p><p>Here’s my entire&nbsp;<code>Program.cs</code>&nbsp;in&nbsp;<code>AppHost</code>:</p><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var password = builder.AddParameter("password", secret: true);
var server = builder.AddSqlServer("server", password, 1433)
        .WithDataVolume("guitar-data")
        .WithLifetime(ContainerLifetime.Persistent);

var db = server.AddDatabase("guitardb");

var cache = builder.AddRedis("cache")
            .WithRedisInsight()
            .WithLifetime(ContainerLifetime.Persistent);

var api = builder.AddProject&lt;Projects.Api&gt;("api")
    .WithReference(db)
    .WithReference(cache)
    .WaitFor(db);

builder.AddProject&lt;Projects.Frontend&gt;("frontend")
    .WithReference(api)
    .WaitFor(api)
    .WithExternalHttpEndpoints();

builder.Build().Run();
</code></pre><h3 id="update-our-api-to-use-redis">Update Our API to Use Redis</h3><p>How do we update the API to use Redis? Let’s sprinkle some minimal caching over the&nbsp;<code>GET /guitars</code>&nbsp;endpoint. After installing the&nbsp;<code>StackExchange.Redis</code>&nbsp;package, we can add a decorator to use output caching.</p><pre><code class="language-csharp">app.UseOutputCache();

app.MapGet("/guitars",
   [OutputCache(Duration = 30)] async (GuitarStoreContext db) =&gt;
       await db.Guitars
               .OrderBy(g =&gt; g.Brand).ThenBy(g =&gt; g.Model)
               .Select(g =&gt; new { g.Id, g.Brand, g.Model, g.Series, g.Price, g.SalePrice })
               .ToListAsync());
</code></pre><p>The output caching middleware can now intercept requests after Aspire registers the Redis store. For testing, we are using a 30-second TTL, but once we go live we can adjust it through configuration.</p><p>Let’s now run the solution and open the dashboard. Our resources keep building up.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/dashboard-with-cache.png?sfvrsn=98b2ccb1_2" class="kg-image" alt="dashboard with cache" loading="lazy" width="1206" height="431"></figure><p>If we browse to our Redis Insight URL, we can see the cache!</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/redis-insight.png?sfvrsn=b5f375f3_2" class="kg-image" alt="redis insight" loading="lazy" width="1266" height="665"></figure><p>When we fire off some calls, we now see an end-to-end request completing in under 3.43ms. Not bad!</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/redis-traces.png?sfvrsn=d82f2884_2" class="kg-image" alt="redis traces" loading="lazy" width="1201" height="309"></figure><p>With SQL Server and Redis in play, our dashboard now shows a dependency graph pointing to both SQL and Redis nodes.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-08/dependency-graph.png?sfvrsn=dca781a0_2" class="kg-image" alt="dependency graph" loading="lazy" width="1068" height="822"></figure><h3 id="developers-are-happy">Developers Are Happy</h3><p>Before Aspire (and Docker containers), can you imagine all the work getting a new developer access to a local environment with multiple APIs, logging, a SQL server and a Redis instance?</p><p>Now, here’s all we need to do:</p><pre><code class="language-bash">git clone https://github.com/davesguitarshop
cd inventory
dotnet run --project GuitarShop.AppHost
</code></pre><p>With one single command we restore NuGet packages, build projects, start our SQL Server and Redis containers, launch our dashboard and open a browser tab at&nbsp;<code>https://localhost:5001</code>. No SQL installations, no&nbsp;<code>docker compose up</code>&nbsp;and no “What ports do we need to use again?” What a world.</p><h3 id="a-sneak-peek-getting-to-the-cloud">A Sneak Peek: Getting to the Cloud</h3><p>While developer happiness is huge, the real payoff comes when we push up to the cloud—to Azure Container Apps, for example. Because the same&nbsp;<code>AppHost</code>&nbsp;definition travels with us, the pipeline only needs:</p><pre><code class="language-yaml">az containerapp up \
  --name guitar-shop \
  --resource-group guitar-shop-rg \
  --subscription guitar-shop-prd
</code></pre><p>YAML</p><p>As a result, Aspire’s Azure Container App extension will map:</p><ul><li><code>AddSqlServer</code>&nbsp;- Azure SQL (or bring your own image)</li><li><code>AddRedis</code>&nbsp;- Azure Cache for Redis (or your own image)</li><li>Health probes - Kubernetes-style liveness and readiness endpoints</li><li>OTLP - Azure Monitor / AppInsights</li></ul><p>We will have much more in Part 6—stay tuned!</p><h2 id="wrapping-up-and-what%E2%80%99s-next">Wrapping Up (And What’s Next)</h2><p>We just replaced a huge&nbsp;<code>docker-compose.yml</code>, a half‑dozen environment‑variable gymnastics and a README full of “run this before that” commands with just a few lines of C#—all discoverable from IntelliSense. Are you not entertained?</p><p>Key takeaways:</p><ul><li><strong>Integrations are resources, not chores.</strong>&nbsp;After declaring intent with&nbsp;<code>AddSqlServer</code>&nbsp;and&nbsp;<code>AddRedis</code>, Aspire handles images, ports and health.</li><li>Connection strings flow automatically.</li><li><strong>Observability is built in.</strong>&nbsp;Every query, cache hit and exception shows up in the dashboard with zero extra code.</li><li><strong>Local developer setup is trivial.</strong>&nbsp;New devs run one command and start coding.</li><li><strong>Portability.</strong>&nbsp;The same AppHost definition deploys to Azure Container Apps, AKS or Docker Swarm with minimal tweaks.</li></ul><p>In&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-5-orchestration-service-discovery?ref=daveabrock.com">Part 5, we’ll dive into service discovery and orchestration</a>—how Aspire lets services talk to each other without hard‑coding URLs and how Polly policies keep things resilient when the network gets mad.</p><p>Until then, happy coding and see you soon!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 3: Service Defaults ]]></title>
        <description><![CDATA[ This post was originally published on the Telerik Developer Blog.

This is the third part of a six-part exploratory series on .NET Aspire.

 * Part 1: What Is .NET Aspire?
 * Part 2: Exploring the Developer Dashboard
 * This post (Part 3): Service Defaults
 * Part 4: Integrations
 * Part 5: Orchestration and Service Discovery ]]></description>
        <link>https://www.daveabrock.com/2025/08/13/net-aspire-3-service-defaults/</link>
        <guid isPermaLink="false">68f7c6f9353aec0001640ead</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 13 Aug 2025 12:50:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1569012871812-f38ee64cd54c?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDI2fHxwcm9ncmFtbWVyfGVufDB8fHx8MTc2MTA2ODk4MXww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published on the <a href="https://www.telerik.com/blogs/net-aspire-3-service-defaults?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p><em>This is the third part of a six-part exploratory series on .NET Aspire.</em></p><ul><li>Part 1:&nbsp;What Is .NET Aspire?</li><li>Part 2:&nbsp;Exploring the Developer Dashboard</li><li><strong>This post</strong>&nbsp;(Part 3): Service Defaults</li><li>Part 4:&nbsp;Integrations</li><li>Part 5:&nbsp;Orchestration and Service Discovery</li><li>Part 6: Deployment using Azure Container Apps</li></ul><p>In the first installment of this series, we said hi to .NET Aspire, Microsoft’s opinionated toolkit for building cloud-ready applications. In the sequel, we peeked at the Developer Dashboard to show how we can add observability with zero extra code.</p><p>Now, we want to answer the following question from your boss: “How do we make every service in our solution have consistency without having to copy and paste hundreds of lines of boilerplate into every project?”</p><p>“It depends” won’t get you out of this one, friend. The answer lies with Aspire’s service defaults. With it, you can attach a single&nbsp;<code>builder.AddServiceDefaults()</code>&nbsp;to your app and it immediately receives:</p><ul><li>OpenTelemetry tracing, logging and metrics wired to your favorite exporter</li><li>Health-check endpoints that distinguish “alive” from “ready”</li><li>Service discovery so in-cluster, service-to-service calls work without hard-coded URLs</li><li>An opinionated Polly-powered resilience pipeline with time-outs, retries and circuit breakers</li></ul><p>Let’s get started, shall we?</p><h2 id="why-bother-with-service-defaults">Why Bother with Service Defaults?</h2><p>As we discussed in our first post, building services can get quite complicated with you having to sprinkle logging, tracing, retries, Docker configs, health checks and whatever else you need.</p><p>With .NET Aspire’s premise to be cloud-ready by default, you can instead reference&nbsp;<code>ServiceDefaults</code>&nbsp;once and instantly have an opinionated baseline that works the same everywhere, whether it’s on your laptop or inside Azure Container Apps. These conventions are tightly coupled with integrations that spin up the infrastructure you need (like SQL Server, Redis and Key Vault)—all with a single line of C#!</p><p>Everything is then expressed as C# code inside your&nbsp;<code>AppHost</code>&nbsp;project, so you can version control your application’s topology just like application logic.</p><p>Since conventions are expressed in one location, a future change—like changing from Honeycomb to Azure Monitor—is a one-line edit.</p><p>Let’s now look at some code and see how it all works.</p><h2 id="looking-inside-the-servicedefaults-project">Looking Inside the ServiceDefaults Project</h2><p>When you create a new Aspire app, or add Aspire to your existing solution, you’ll see a project named&nbsp;<code>ServiceDefaults</code>.</p><p>Let’s look in the&nbsp;<code>ServiceDefaults</code>&nbsp;project. Open the file&nbsp;<code>Extensions.cs</code>&nbsp;(or something similar). You should see an&nbsp;<code>AddServiceDefaults</code>&nbsp;extension method that looks something like this:</p><pre><code class="language-csharp">public static TBuilder AddServiceDefaults&lt;TBuilder&gt;(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    builder.ConfigureOpenTelemetry();
    builder.AddDefaultHealthChecks();
    builder.Services.AddServiceDiscovery();
    builder.Services.ConfigureHttpClientDefaults(http =&gt;
    {
        http.AddStandardResilienceHandler();
        http.AddServiceDiscovery();
    });

    return builder;
}
</code></pre><p>Let’s unpack this code.</p><p><strong>Note</strong>: The resiliency and service discovery parts deserve a treatment of their own and will be discussed in detail in Part 5 of our series.</p><h3 id="opentelemetry-configuration">OpenTelemetry Configuration</h3><p>When we look at&nbsp;<code>builder.ConfigureOpenTelemetry</code>, .NET Aspire provides a set of opinionated defaults for OpenTelemetry.</p><p>By default, Aspire adds:</p>
<!--kg-card-begin: html-->
<table style="background-color: rgb(255, 255, 255); border-collapse: collapse; border-spacing: 0px; width: 670px; color: rgb(56, 63, 85); font-family: Metric, Arial, sans-serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><thead><tr><th data-role="resizable" style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Signal</th><th style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Instrumentations</th></tr></thead><tbody><tr><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Logs</td><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;"><code class="inline-code" style="background-color: rgb(238, 245, 255) !important; font-size: 0.8em !important; word-break: break-word; display: inline !important; line-height: 1.4 !important; padding: 0px 5px !important;">Microsoft.Extensions.Logging</code><span>&nbsp;</span>OTLP exporter</td></tr><tr><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Traces and spans</td><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">ASP.NET Core, HttpClient, gRPC, SqlClient, EF Core, Redis</td></tr><tr><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Metrics</td><td style="text-align: left; vertical-align: top; width: 323.5px; border-width: 1px; border-style: dotted; border-color: rgb(189, 189, 186); padding: 5px; margin: 5px;">Runtime, ASP.NET Core, HttpClient, SqlClient</td></tr></tbody></table>
<!--kg-card-end: html-->
<p>These are all viewable from the Aspire dashboard that we reviewed in the previous post. For the OTLP exporter, it easily integrates with your telemetry. For example, in Azure Container Apps the exporter points at Azure Monitor.</p><p>None of this is magic. If you scroll down in your&nbsp;<code>Extensions.cs</code>, you can inspect the&nbsp;<code>ConfigureOpenTelemetry</code>&nbsp;extension method to learn more.</p><pre><code class="language-csharp">public static TBuilder ConfigureOpenTelemetry&lt;TBuilder&gt;(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    builder.Logging.AddOpenTelemetry(logging =&gt;
    {
        logging.IncludeFormattedMessage = true;
        logging.IncludeScopes = true;
    });

    builder.Services.AddOpenTelemetry()
        .WithMetrics(metrics =&gt;
        {
            metrics.AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddRuntimeInstrumentation();
        })
        .WithTracing(tracing =&gt;
        {
            tracing.AddSource(builder.Environment.ApplicationName)
                .AddAspNetCoreInstrumentation()
                // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
                //.AddGrpcClientInstrumentation()
                .AddHttpClientInstrumentation();
        });

    builder.AddOpenTelemetryExporters();

    return builder;
}
</code></pre><p>Configuring your exporter is super easy. Because the exporter URL comes from&nbsp;<code>OTEL_EXPORTER_OTLP_ENDPOINT</code>, changing where telemetry flows is an easy one-liner:</p><pre><code class="language-bash">export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
</code></pre><p>In the&nbsp;<code>AddOpenTelemetryExporters</code>, you’ll see it in action. Need Azure Monitor instead? Uncomment the relevant block in&nbsp;<code>AddOpenTelemetryExporters</code>, supply an&nbsp;<code>APPLICATIONINSIGHTS_CONNECTION_STRING</code>, and call it a day.</p><pre><code class="language-csharp">private static TBuilder AddOpenTelemetryExporters&lt;TBuilder&gt;(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

    if (useOtlpExporter)
    {
        builder.Services.AddOpenTelemetry().UseOtlpExporter();
    }

    // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
    //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
    //{
    //    builder.Services.AddOpenTelemetry()
    //       .UseAzureMonitor();
    //}

    return builder;
}</code></pre><h3 id="default-health-checks">Default Health Checks</h3><p>Moving on: What does&nbsp;<code>builder.AddDefaultHealthChecks()</code>&nbsp;get us? This powerful line adds a set of opinionated defaults for health checks, which can be used by systems and applications to see if your app is ready.</p><p>The&nbsp;<code>AddDefaultHealthChecks</code>&nbsp;method adds a default liveness check to check if the application is responsive.</p><pre><code class="language-csharp">public static TBuilder AddDefaultHealthChecks&lt;TBuilder&gt;(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    builder.Services.AddHealthChecks()
        // Add a default liveness check to ensure app is responsive
        .AddCheck("self", () =&gt; HealthCheckResult.Healthy(), ["live"]);

    return builder;
}
</code></pre><p>You can see how this all works in the&nbsp;<code>MapDefaultEndpoints</code>&nbsp;extension method, where it exposes a&nbsp;<code>/health</code>&nbsp;endpoint and an&nbsp;<code>/alive</code>&nbsp;endpoint. The&nbsp;<code>/health</code>&nbsp;endpoint illustrates if the app is running and ready to receive requests. The&nbsp;<code>/alive</code>&nbsp;endpoint indicates if the app is running or must be restarted because of a crash.</p><pre><code class="language-csharp">public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
    // Adding health checks endpoints to applications in non-development environments has security implications.
    // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
    if (app.Environment.IsDevelopment())
    {
        // All health checks must pass for app to be considered ready to accept traffic after starting
        app.MapHealthChecks("/health");

        // Only health checks tagged with the "live" tag must pass for app to be considered alive
        app.MapHealthChecks("/alive", new HealthCheckOptions
        {
            Predicate = r =&gt; r.Tags.Contains("live")
        });
    }

    return app;
}
</code></pre><p>As you can see the defaults are for&nbsp;<em>development only</em>. You must opt into production exposure.</p><p>The health checks also come built in with Aspire’s various integrations. For example, the&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/database/sql-server-integration?tabs=dotnet-cli%2Cssms&ref=daveabrock.com#hosting-integration-health-checks">health check for SQL Server</a>&nbsp;verifies that SQL Server is running and that a connection can be established.</p><h2 id="create-a-custom-service-defaults-project">Create a Custom Service Defaults Project</h2><p>If you look at the&nbsp;<code>MyApp.ServiceDefaults.csproj</code>, you’ll notice a&nbsp;<code>FrameworkReference</code>&nbsp;dependency on&nbsp;<code>Microsoft.AspNetCore.App</code>.</p><pre><code class="language-xml">&lt;FrameworkReference Include="Microsoft.AspNetCore.App" /&gt;
</code></pre><p>That reference brings in the entire ASP.NET Core shared framework (with Kestrel, MVC, SignalR and so on).</p><p>In certain situations, you might not want this:</p><ul><li><strong>Non-HTTP workloads</strong>: Background workers or queue processors don’t need Kestrel.</li><li><strong>Serverless hosts</strong>: Azure Functions ships their own ASP.NET Core copy. A second copy can cause binding conflicts.</li><li><strong>Reusable class libraries</strong>: Transitive framework references force consumer apps to carry ASP.NET Core. What if the library is UI-agnostic?</li></ul><p>In that case, you can create a custom service defaults project. According to the Microsoft Docs, you can create a new class library project and add its dependencies to the project file. Check out the&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/service-defaults?ref=daveabrock.com#custom-service-defaults">docs for more information</a>.</p><h2 id="wrapping-up">Wrapping Up</h2><p>Service Defaults are the unsung hero of .NET Aspire. They compress all the OpenTelemetry wiring, health probes, discovery and Polly policies into one method call. As a result, every service behaves predictably, telemetry is always on and your new hire ramps up quickly (think minutes, not days).</p><p>In the next installment we’ll explore integrations. We’ll see how Aspire spins up SQL Server and Redis containers—all orchestrated from our AppHost. Stay tuned!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 2: Exploring the Developer Dashboard ]]></title>
        <description><![CDATA[ This post was originally published on the Telerik Developer Blog.

This is the second part of a six-part exploratory series on .NET Aspire.

 * Part 1: What Is .NET Aspire?
 * This post (Part 2): Exploring the Developer Dashboard
 * Part 3: Service Defaults
 * Part 4: Integrations
 * Part 5: Orchestration and Service Discovery ]]></description>
        <link>https://www.daveabrock.com/2025/07/15/net-aspire-2-exploring-the-developer-dashboard/</link>
        <guid isPermaLink="false">68f690970ac93000018c81f6</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 15 Jul 2025 14:43:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1526628953301-3e589a6a8b74?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDV8fGRhc2hib2FyZHxlbnwwfHx8fDE3NjA5ODk0NjB8MA&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published on the <a href="https://www.telerik.com/blogs/net-aspire-2-developer-dashboard?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p><em>This is the second part of a six-part exploratory series on .NET Aspire.</em></p><ul><li>Part 1: What Is .NET Aspire?</li><li><strong>This post (Part 2)</strong>: Exploring the Developer Dashboard</li><li>Part 3: Service Defaults</li><li>Part 4: Integrations</li><li>Part 5: Orchestration and Service Discovery</li><li>Part 6: Deployment Using Azure Container Apps</li></ul><p>Hello again, friends, and welcome back. If you missed the&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-1-what-is-net-aspire?ref=daveabrock.com">intro to about .NET Aspire</a>, feel free to check that out before reading the rest of this piece. Today, we’ll focus on my favorite feature:&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash&ref=daveabrock.com">the developer dashboard</a>. The dashboard allows you to track your app in real-time through a single user interface.</p><p>Before we get there, I want to first walk you through the project we’ll be using: Dave’s Guitar Shop. If you remember, here’s the initial high-level architecture of my Aspire-less solution.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/phase2-api.png?sfvrsn=b8670b18_2" class="kg-image" alt="phase2 api" loading="lazy" width="1152" height="690"></figure><h2 id="exploring-the-project">Exploring the Project</h2><p>For this post, we’ll be focusing on the&nbsp;<code>/inventory</code>&nbsp;API. This API is consumed by a Blazor server-side web app. I’ll walk you through&nbsp;<em>key parts</em>&nbsp;of the solution.</p><h3 id="the-api-code">The API Code</h3><p>We are using a quick ASP.NET Core Minimal API with basic CRUD (create, read, update, delete) operations. The data is persisted to a containerized SQL server and uses Entity Framework for query-ability.</p><p>Here’s a sample of the API calls:</p><pre><code class="language-csharp">app.MapGet("/guitars", async (GuitarStoreContext db) =&gt;
{
    var list = await Queries.GetAllGuitars(db).ToListAsync();
    return Results.Ok(list);
});

app.MapGet("/guitars/{id:guid}", async (Guid id, GuitarStoreContext db) =&gt;
    await Queries.GetGuitarById(db, id) is { } dto
        ? Results.Ok(dto)
        : Results.NotFound());

app.MapPost("/guitars", async (Guitar guitar, GuitarStoreContext db) =&gt;
{
    db.Guitars.Add(guitar);
    await db.SaveChangesAsync();
    return Results.Created($"/guitars/{guitar.Id}", guitar);
});

app.MapPut("/guitars/{id:guid}", async (Guid id, Guitar updated, GuitarStoreContext db) =&gt;
{
    var guitar = await db.Guitars.FindAsync(id);
    if (guitar is null) return Results.NotFound();

    db.Entry(guitar).CurrentValues.SetValues(updated);
    await db.SaveChangesAsync();
    return Results.NoContent();
});

app.MapDelete("/guitars/{id:guid}", async (Guid id, GuitarStoreContext db) =&gt;
{
    var guitar = await db.Guitars.FindAsync(id);
    if (guitar is null) return Results.NotFound();

    db.Guitars.Remove(guitar);
    await db.SaveChangesAsync();
    return Results.NoContent();
});
</code></pre><h3 id="the-database">The Database</h3><p>From the SQL side, my&nbsp;<code>Dockerfile</code>&nbsp;is using the&nbsp;<a href="http://mcr.microsoft.com/mssql/server:2022-latest?ref=daveabrock.com" rel="nofollow"><code>mcr.microsoft.com/mssql/server:2022-latest</code></a>&nbsp;image. If you’re interested in learning more,&nbsp;<a href="https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-linux-ver16&preserve-view=true&tabs=cli&pivots=cs1-bash&ref=daveabrock.com#pull-the-container-image-from-the-registry-1">check out the Microsoft documentation</a>. Right now, I’m using Docker Compose to manage the container.</p><p>In the next post, we’ll discuss how to simplify this with .NET Aspire.</p><h2 id="the-blazor-app">The Blazor App</h2><p>Finally, this API is consumed by a Blazor web app. For now, we’ll show the main component where we load all the guitars in inventory.</p><pre><code class="language-razor">@page "/"
@inject BackendHttpClient HttpClient

&lt;PageTitle&gt;Guitars&lt;/PageTitle&gt;

&lt;div class="container py-4"&gt;
    &lt;h1 class="display-6 mb-4 d-flex align-items-center gap-2"&gt;
        &lt;span&gt;🎸&lt;/span&gt; Guitar Catalog
    &lt;/h1&gt;

    @if (_guitars is null)
    {
        &lt;div class="d-flex align-items-center" aria-label="Loading"&gt;
            &lt;div class="spinner-border text-primary me-2" role="status"&gt;
                &lt;span class="visually-hidden"&gt;Loading…&lt;/span&gt;
            &lt;/div&gt;
            &lt;span&gt;Loading guitars…&lt;/span&gt;
        &lt;/div&gt;
    }
    else if (!_guitars.Any())
    {
        &lt;p class="text-muted"&gt;No guitars found.&lt;/p&gt;
    }
    else
    {
        &lt;div class="card shadow-sm"&gt;
            &lt;div class="card-header bg-primary text-white fw-semibold"&gt;
                Guitar List
            &lt;/div&gt;
            &lt;div class="table-responsive"&gt;
                &lt;table class="table table-hover mb-0 align-middle"&gt;
                    &lt;thead class="table-light"&gt;
                        &lt;tr class="small text-uppercase"&gt;
                            &lt;th scope="col"&gt;Brand&lt;/th&gt;
                            &lt;th scope="col"&gt;Model&lt;/th&gt;
                            &lt;th scope="col"&gt;Series&lt;/th&gt;
                            &lt;th scope="col" class="text-end"&gt;Price&lt;/th&gt;
                        &lt;/tr&gt;
                    &lt;/thead&gt;
                    &lt;tbody&gt;
                        @foreach (var g in _guitars!)
                        {
                            &lt;tr&gt;
                                &lt;td&gt;@g.Brand&lt;/td&gt;
                                &lt;td&gt;@g.Model&lt;/td&gt;
                                &lt;td&gt;@g.Series&lt;/td&gt;
                                &lt;td class="text-end"&gt;@g.Price.ToString("C")&lt;/td&gt;
                            &lt;/tr&gt;
                        }
                    &lt;/tbody&gt;
                &lt;/table&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    }
&lt;/div&gt;

@code {
    private List&lt;GuitarDto&gt;? _guitars;

    protected override async Task OnInitializedAsync()
    {
        _guitars = await HttpClient.GetGuitarsAsync();
    }
}
</code></pre><p>And with that, we have a table that lists everything in inventory.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/get-guitars.png?sfvrsn=d388b5e_2" class="kg-image" alt="get guitars" loading="lazy" width="989" height="338"></figure><h2 id="adding-the-dashboard">Adding the Dashboard</h2><p>Now that we’ve got an app, let’s add some observability to it by using the .NET Aspire dashboard.</p><h3 id="which-dashboard-to-choose">Which Dashboard to Choose?</h3><p>We have two choices: using&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash&ref=daveabrock.com#standalone-mode">standalone mode</a>&nbsp;or&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash&ref=daveabrock.com#use-the-dashboard-with-net-aspire-projects">a .NET Aspire project</a>.</p><p>With standalone mode, you can pull a Docker image and use it without the rest of .NET Aspire. Let’s say your Operations team needs a “single pane of glass” for all your services—say, half of your services are in .NET and the rest are in Node or Python.</p><p>One single dashboard can ingest everyone’s OpenTelemetry (OTLP) traffic without worrying about who wrote the code. Additionally, it can run as its own container or deployment and stay up even if your app crashes.</p><p>We’ll be using the built-in Aspire dashboard. This shines during our inner-loop process: change code, hit F5 in Visual Studio and watch the traces. That way, the dashboard appears automatically and is wired to every container, project and secret we know about.</p><p>With that in mind, we’ll start to Aspire-ify our project.</p><h2 id="add-aspire-to-our-existing-application">Add Aspire to Our Existing Application</h2><p>There are many ways to add Aspire to an existing app; for us, we’ll do it through Visual Studio tooling.</p><p>In Visual Studio, let’s create a new project and search for the&nbsp;<strong>.NET Aspire App Host</strong>&nbsp;template.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/add-aspire-project.png?sfvrsn=41ceba73_2" class="kg-image" alt="add aspire project" loading="lazy" width="681" height="344"></figure><p>Once you add the project, you’ll see two new projects added to Solution Explorer: an AppHost project and a ServiceDefaults library project. Let’s talk about the AppHost project (we will cover ServiceDefaults in detail in our next post).</p><h3 id="the-apphost-project">The AppHost Project</h3><p>We can think of AppHost as a command center for our application. Instead of juggling a bunch of configs, Docker Compose files and scripts, this project has a single launch profile that boots our app and its dependencies with access to one fully wired dashboard.</p><p>By default, the file includes these two lines that really pack a punch:</p><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);
builder.Build().Run();
</code></pre><p>This code scans every referenced project or container image, builds a dependency graph, injects environment variables (like connection strings and secrets), and launches the .NET Aspire dashboard.</p><p>How does it all work?</p><ol><li>AppHost starts.</li><li>For each project, it runs with a generated launch command.</li><li>It runs&nbsp;<code>docker run</code>&nbsp;behind the scenes for each container.</li><li>It sets environment variables like&nbsp;<code>Api__BaseAddress</code>&nbsp;and&nbsp;<code>ConnectionStrings__DefaultConnection</code>.</li><li>The service defaults (to be discussed next time!) discover the dashboard endpoint at&nbsp;<code>OTEL_EXPORTER_OTLP_ENDPOINT</code>.</li><li>You have a glorious dashboard to use out of the box.</li></ol><p>Before we launch the app and see it in action, let’s add a few lines of code to our&nbsp;<code>AppHost</code>&nbsp;project.</p><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var api = builder.AddProject&lt;Projects.Api&gt;("api");

builder.AddProject&lt;Projects.Frontend&gt;("frontend")
    .WithReference(api)
    .WaitFor(api)
    .WithExternalHttpEndpoints();

builder.Build().Run();
</code></pre><p>From a high level, here’s what happens:</p><ol><li><code>DistributedApplication.CreateBuilder(args)</code>&nbsp;creates a builder that will handle every service, container and config value.</li><li><code>AddProject&lt;Projects.Api&gt;("api")</code>&nbsp;tells the builder to spin up the API container and have it addressable as&nbsp;<code>api</code>&nbsp;for other services to reference.</li><li>For the frontend,&nbsp;<code>AddProject&lt;Projects.Frontend&gt;("frontend")</code>&nbsp;registers the UI and&nbsp;<code>WithReference(api)</code>&nbsp;hands the UI the API’s base URL. Then,&nbsp;<code>WaitFor(api)</code>&nbsp;makes the UI wait until the API is healthy. Finally,&nbsp;<code>WithExternalHttpEndpoints()</code>&nbsp;exposes the UI so a browser can reach it.</li></ol><p>There is much, much more we can (and will!) do here, but for now, this will help us “connect” the UI with the API in our dashboard.</p><p>Enough already! Let’s see it.</p><h2 id="the-dashboard-in-action">The Dashboard in Action</h2><p>Right away, we see a unified interface for our application. Here you can easily navigate to our services and quickly access logs, traces and metrics in one spot.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/dashboard-home.png?sfvrsn=8feaf08e_2" class="kg-image" alt="dashboard home" loading="lazy" width="1017" height="440"></figure><p>If we click over to the Console section, you can select from the&nbsp;<code>api</code>&nbsp;or&nbsp;<code>frontend</code>&nbsp;logs. No more painful toggling between multiple consoles!</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/api.png?sfvrsn=a21de61c_2" class="kg-image" alt="api" loading="lazy" width="1010" height="566"></figure><p>We have structured logging that allows us to easily filter on what we need, like a SQL command:</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/structured.png?sfvrsn=290f39b2_2" class="kg-image" alt="structured" loading="lazy" width="1246" height="838"></figure><p>With traces, we can run through our dependencies and how long they take. For now, we can see details of the HTTP request and the SQL call.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/sql.png?sfvrsn=4217c25c_2" class="kg-image" alt="sql" loading="lazy" width="981" height="246"></figure><p>We also have pre-baked metrics and a dependency graph (which will get more interesting over this series, I promise).</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/graph.png?sfvrsn=64eb875b_2" class="kg-image" alt="graph" loading="lazy" width="870" height="643"></figure><p>If you click&nbsp;<code>api</code>, you can get information on health checks and the environment variables Aspire uses.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-06/vars.png?sfvrsn=28d4f33f_2" class="kg-image" alt="vars" loading="lazy" width="1225" height="687"></figure><p>There are many more features I don’t have space to cover, like:&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/explore?ref=daveabrock.com#dashboard-authentication">dashboard authentication</a>,&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/explore?ref=daveabrock.com#metrics-page">metrics</a>&nbsp;and&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/copilot?ref=daveabrock.com">GitHub Copilot integration</a>. I’d suggest building a new Aspire project and clicking around for yourself. I don’t think I can go back to local debugging and tracing before Aspire.</p><h2 id="wrapping-up">Wrapping Up</h2><p>I hope you enjoyed learning more about the .NET Aspire doashboarding capabilities. Next time, we’ll work on integrations and smart defaults, where we can add our SQL Server container with just a few lines of code.</p><p>See you there, and happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET Aspire 1: What is .NET Aspire? ]]></title>
        <description><![CDATA[ This post was originally published on the Telerik Developer Blog.

This is the first part of a six-part exploratory series on .NET Aspire.

 * This post (part 1): What Is .NET Aspire?
 * Part 2: Exploring the Developer Dashboard
 * Part 3: Service Defaults
 * Part 4: Integrations
 * Part 5: Orchestration and Service Discovery ]]></description>
        <link>https://www.daveabrock.com/2025/06/24/net-aspire-1-what-is-net-aspire/</link>
        <guid isPermaLink="false">68f68f8e0ac93000018c81de</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 24 Jun 2025 14:40:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1580894894513-541e068a3e2b?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDM0fHxzb2Z0d2FyZSUyMGVuZ2luZWVyfGVufDB8fHx8MTc2MDk4OTE5MHww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published on the <a href="https://www.telerik.com/blogs/net-aspire-1-what-is-net-aspire?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p><em>This is the first part of a six-part exploratory series on .NET Aspire.</em></p><ul><li><strong>This post (part 1)</strong>: What Is .NET Aspire?</li><li>Part 2: Exploring the Developer Dashboard</li><li>Part 3: Service Defaults</li><li>Part 4: Integrations</li><li>Part 5: Orchestration and Service Discovery</li><li>Part 6: Deployment Using Azure Container Apps</li></ul><p>Over the last few years, I’ve been chronically tired and I don’t know why. I hydrate, I exercise, I get decent sleep and I even eat a vegetable or two. In short, I’m Wisconsin healthy. (85% healthy habits, and 15% cheese curds and beer.)</p><p>I haven’t been able to figure out what’s wrong, and the doctors haven’t either. But after much reflection and some late nights, I figured it out.</p><p>I work in cloud-native development.</p><h2 id="progress-albeit-slow">Progress, Albeit Slow</h2><p>Once upon time—a simpler time, no doubt—we shipped hulking monoliths. One app, one deploy and one big, beautiful ball of code. Need to add a feature? Crack open the behemoth, sprinkle in a few classes and pray the whole thing still compiles on Friday afternoon.</p><p>Then came microservices and our “make everything smaller” movement. Suddenly that single code pile shattered into a mess of bite-sized services, each with its own repo, pipeline and database. Debugging turned into a game of distributed whack-a-mole, all scattered across 12 clusters like digital confetti.</p><p>Deploying code used to be “copy files to the server.” Today it’s a&nbsp;<code>helm upgrade</code>, a Docker registry push, a secret rotation, configuration updates and a moment of silence for the build agent. Progress? Absolutely. Simple and enjoyable? Never.</p><h2 id="gains-and-gains">Gains ... And Gains</h2><p>But here’s the thing: The chaos isn’t for nothing. We’ve gained on-demand infrastructure, independent deployments and self-healing resilience that would make past Dave weep. Spinning up a replica database takes minutes, not days. Rolling back a troubled service is a one-line re-deploy, not an all-hands war room.</p><p>Those wins are real—but so is the cognitive load. Every new repo adds another Dockerfile, another liveness probe and another chance to typo your configuration files. Wouldn’t it be nice to keep the benefits without the YAML-induced migraines?</p><p>Imagine an opinionated set of tools that wrap all those best practices—service discovery, health checks, telemetry, secret management and more—into sane defaults you don’t have to wire up from scratch. Something that spins up your entire stack with a single command, shows traces and logs in one dashboard, and makes production deployment a breeze.</p><h2 id="net-aspire-for-cloud-native-development">.NET Aspire for Cloud-Native Development</h2><p>We’ll be looking at&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview?ref=daveabrock.com">.NET Aspire</a>, your building blocks for working with the complexities of cloud-native development. It doesn’t erase the complexity but organizes it into parts that snap together:</p><ul><li>You can bootstrap your app with a single command, and&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/reference/aspire-faq?ref=daveabrock.com#why-choose--net-aspire-over-docker-compose-for-orchestration-">no more Docker Compose gymnastics</a>.</li><li>A unified developer dashboard for distributed tracing, logs, metrics and container monitoring in a single tab. No more having six debugging windows for your frontend and all your APIs.</li><li>Aspire includes smart defaults to cover OpenTelemetry, Polly retries, secret rotation and health probes.</li><li>No more hard-coding URLs with&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/service-discovery/overview?ref=daveabrock.com">configuring service discovery</a>&nbsp;at development time.</li><li>Component support lets you drop in PostgreSQL, Redis, Azure Service Bus, Key Vault and more with one line of code. Aspire pulls the container image, wires the connection string, adds health probes and even injects secrets for you—all&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/integrations-overview?ref=daveabrock.com">powered by its integration library</a>.</li></ul><h2 id="the-project-this-series-will-explore">The Project This Series Will Explore</h2><p>Get comfortable: We’re going to spend the next four posts applying .NET Aspire to an existing application. Welcome to Dave’s Guitar Shop. (If you have free inventory, feel free to pass it my way.)</p><p>Dave’s Guitar Shop started as a regular monolithic application. It had a Blazor web app and a single API project that handled identity, product inventory and orders.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-05/phase1-api.png?sfvrsn=93c2dcda_2" class="kg-image" alt="phase1 api" loading="lazy" width="711" height="283"></figure><p>Dave’s Guitar Shop is growing and now we have several development teams. We’ve decided to leverage microservices, and our high-level architecture is looking a bit different.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-05/phase2-api.png?sfvrsn=90e4f641_2" class="kg-image" alt="phase2 api" loading="lazy" width="1152" height="690"></figure><p>Keep in mind this is just a high-level view! We still want to add telemetry services, some queuing and maybe even some OpenAI services. We’re also having scaling and resiliency issues and want to deploy to Azure Container Apps. This is a great use case for .NET Aspire.</p><p>Throughout these next four posts, we’re going to show off the benefits of .NET Aspire. In the&nbsp;<a href="https://www.telerik.com/blogs/net-aspire-2-developer-dashboard?ref=daveabrock.com">next post</a>, I’ll show you how to add .NET Aspire to an existing project and the benefits of the Developer Dashboard. Stay tuned, and I’ll see you soon!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ What Is DeepSeek? Dive in Using DeepSeek, .NET Aspire, and Blazor ]]></title>
        <description><![CDATA[ This post was originally posted on the Telerik Developer Blog.

A new AI model has taken the tech world, and the actual world, by storm.

It performs close to, or better than, the GPT 4o, Claude and Llama models. It was developed at a cost of $1.3 billion (rather ]]></description>
        <link>https://www.daveabrock.com/2025/02/04/what-is-deepseek-dive-in-using-deepseek-net-aspire-and-blazor/</link>
        <guid isPermaLink="false">68f68a720ac93000018c8190</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 04 Feb 2025 14:23:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1674027444485-cec3da58eef4?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDJ8fGFpfGVufDB8fHx8MTc2MDk4ODcxNXww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally posted on the <a href="https://www.telerik.com/blogs/what-deepseek-dive-using-deepseek-net-aspire-blazor?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p>A new AI model has taken the tech world, and the actual world, by storm.</p><p>It performs close to, or better than, the GPT 4o, Claude and Llama models. It was developed at a&nbsp;<a href="https://www.deccanherald.com/technology/how-much-did-it-cost-to-train-deepseek-13-bn-not-6-mn-report-3383765?ref=daveabrock.com">cost of $1.3 billion (rather than the originally reported $6 million</a>)—using clever engineering instead of top-tier GPUs. Even better, it was shipped as open-source, allowing anyone in the world to understand it, download it and modify it.</p><p>Have we achieved the democratization of AI, where the power of AI can be in the hands of many and not the few big tech companies who can afford billions of dollars in investment?</p><p>Of course, it’s not that simple. After Chinese startup&nbsp;<a href="https://www.deepseek.com/?ref=daveabrock.com">DeepSeek</a>&nbsp;released&nbsp;<a href="https://arxiv.org/pdf/2501.12948?ref=daveabrock.com">its latest model</a>, it has disrupted stock markets, scared America’s Big Tech giants and incited TMZ-level drama across the tech space. To wit: Are American AI companies overvalued? Can competitive models truly be built at a fraction of the cost? Is this our&nbsp;<a href="https://x.com/pmarca/status/1883640142591853011?ref=daveabrock.com">Sputnik moment in the AI arms race</a>? (I don’t think NASA was able to fork the Sputnik project on GitHub.)</p><p>In a future article, I’ll take a deeper dive into DeepSeek itself and its programming-focused model,&nbsp;<a href="https://deepseekcoder.github.io/?ref=daveabrock.com">DeepSeek Coder</a>. For now, let’s get our feet wet with DeepSeek. Because DeepSeek is built on open source, we can download the models locally and work with them.</p><p>Recently, Progress’ own Ed Charbeneau led a live stream on&nbsp;<a href="https://www.youtube.com/live/p2nvP0Y-cuI?ref=daveabrock.com">running DeepSeek AI with .NET Aspire</a>. In this post, I’ll take a similar approach and walk you through how to get DeepSeek AI working as he did in the stream.</p><blockquote><strong>Note:</strong>&nbsp;This post gets us started; make sure to watch Ed’s stream for a deeper dive.</blockquote><h2 id="our-tech-stack">Our Tech Stack</h2><p>For our tech stack, we’ll be using .NET Aspire. .NET Aspire is an opinionated, cloud-ready stack&nbsp;<a href="https://learn.microsoft.com/en-us/training/modules/introduction-dotnet-aspire/2-what?ref=daveabrock.com">built for .NET-distributed applications</a>. For our purposes today, we’ll be using it to get up and running quickly and to easily manage our containers. I’m not doing .NET Aspire justice, with all its power and capabilities: Check out&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview?ref=daveabrock.com">the Microsoft documentation</a>&nbsp;to learn more.</p><p>Before we get started, make sure you have the following:</p><ul><li><a href="https://docs.docker.com/engine/install/?ref=daveabrock.com">Docker</a>&nbsp;(to get up and running on Docker quickly,&nbsp;<a href="https://docs.docker.com/desktop/?ref=daveabrock.com">Docker Desktop</a>&nbsp;is a great option)</li><li>Visual Studio 2022</li><li>.NET 8 or later</li><li>A basic knowledge of C#, ASP.NET Core and containers</li></ul><h2 id="picking-a-model">Picking a Model</h2><p>To run models locally on our system, we’ll be using Ollama, an open-source tool that allows us to run large language models (LLMs) on our local system. If we head over to&nbsp;<a href="https://ollama.com/search?ref=daveabrock.com">ollama.com</a>, let’s search for&nbsp;<em>deepseek</em>.</p><p>You might be compelled to install&nbsp;<code>deepseek-v3</code>, the new hotness, but it also has a 404 GB download size. Instead, we’ll be using the&nbsp;<a href="https://ollama.com/library/deepseek-r1?ref=daveabrock.com">deepseek-r1 model</a>. It’s less advanced but good enough for testing—it also uses less space, so you don’t need to rent a data center to use it.</p><p>It’s a tradeoff between parameter size and download size. Pick the one that both you and your machine are comfortable with. In this demo, I’ll be using&nbsp;<code>8b</code>, with a manageable 4.9GB download size. Take note of the flavor you are using, as we’ll need to put it in our&nbsp;<code>Program.cs</code>&nbsp;soon.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2025/10/image.png" class="kg-image" alt="" loading="lazy" width="1097" height="749" srcset="https://www.daveabrock.com/content/images/size/w600/2025/10/image.png 600w, https://www.daveabrock.com/content/images/size/w1000/2025/10/image.png 1000w, https://www.daveabrock.com/content/images/2025/10/image.png 1097w" sizes="(min-width: 720px) 720px"></figure><h2 id="set-up-the-aspire-project">Set Up the Aspire Project</h2><p>Now, we can create a new Aspire project in Visual Studio.</p><ol><li>Launch Visual Studio 2022 and select the&nbsp;<strong>Create a new project</strong>&nbsp;option.</li><li>Once the project templates display, search for&nbsp;<em>aspire</em>.</li><li>Select the&nbsp;<strong>.NET Aspire Starter App</strong>&nbsp;template, and click Next.</li></ol><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2025/10/image-2.png" class="kg-image" alt="" loading="lazy" width="1007" height="663" srcset="https://www.daveabrock.com/content/images/size/w600/2025/10/image-2.png 600w, https://www.daveabrock.com/content/images/size/w1000/2025/10/image-2.png 1000w, https://www.daveabrock.com/content/images/2025/10/image-2.png 1007w" sizes="(min-width: 720px) 720px"></figure><ol start="4"><li>Then, click through the prompts to create a project. If you want to follow along, we are using .NET 9.0 and have named the project&nbsp;<strong>DeepSeekDemo</strong>.</li><li>Right-click the&nbsp;<strong>DeepSeekDemo.AppHost</strong>&nbsp;project and click&nbsp;<strong>Manage NuGet Packages…</strong>.</li><li>Search for and install the following NuGet packages. (If you prefer, you can also do it from the&nbsp;<a href="https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-using-the-dotnet-cli?ref=daveabrock.com">.NET CLI</a>&nbsp;or the&nbsp;<a href="https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files?ref=daveabrock.com">project file</a>.)</li></ol><ul><ul><li><code>CommunityToolkit.Aspire.Hosting.Ollama</code></li><li><code>CommunityToolkit.Aspire.OllamaSharp</code></li></ul></ul><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2025/10/image-3.png" class="kg-image" alt="" loading="lazy" width="1011" height="248" srcset="https://www.daveabrock.com/content/images/size/w600/2025/10/image-3.png 600w, https://www.daveabrock.com/content/images/size/w1000/2025/10/image-3.png 1000w, https://www.daveabrock.com/content/images/2025/10/image-3.png 1011w" sizes="(min-width: 720px) 720px"></figure><ol start="7"><li>Now that everything is installed, you can navigate to the&nbsp;<code>Program.cs</code>&nbsp;file in that same project and replace it with the following.</li></ol><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var ollama = builder.AddOllama("ollama")
                .WithDataVolume()
                .WithGPUSupport()
                .WithOpenWebUI();
builder.Build().Run();</code></pre><p>     Here’s a breakdown of what the&nbsp;<code>AddOllama</code>&nbsp;extension method does:</p><ul><ul><li><code>AddOllama</code>&nbsp;adds an Ollama container to the application builder. With that in place, we can add models to the container. These models download and run when the container starts.</li><li><code>WithDataVolume</code>&nbsp;allows us to store the model in a Docker volume, so we don’t have to continually download it every time.</li><li>If you are lucky enough to have GPUs locally, the&nbsp;<code>WithGPUSupport</code>&nbsp;call uses those.</li><li>The&nbsp;<code>WithOpenWebUI</code>&nbsp;call allows us to talk to our chatbot using the&nbsp;<a href="https://docs.openwebui.com/?ref=daveabrock.com">Open WebUI project</a>. This is served by a Blazor front end.</li></ul></ul><ol start="8"><li>Finally, let’s add a reference to our DeepSeek model so we can download and use it. We can also choose to host multiple models down the line.</li></ol><pre><code class="language-csharp">var builder = DistributedApplication.CreateBuilder(args);

var ollama = builder.AddOllama("ollama")
                .WithDataVolume()
                .WithGPUSupport()
                .WithOpenWebUI(); 

var deepseek = ollama.AddModel("deepseek-r1:8b");

builder.Build().Run();</code></pre><h2 id="explore-the-application">Explore the Application</h2><p>Let’s run the application! It’ll take a few minutes for all the containers to spin up. While you’re waiting, you can click over to the logs.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-01/aspire-logs.png?sfvrsn=6900dac6_2" class="kg-image" alt="aspire logs" loading="lazy" width="975" height="298"></figure><p>Once all three containers have a state of&nbsp;<strong>Running</strong>, click into the endpoint for the&nbsp;<code>ollama-openweb-ui</code>&nbsp;container.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-01/openwebui.png?sfvrsn=c65302ac_2" class="kg-image" alt="openwebui" loading="lazy" width="1268" height="303"></figure><p>Once there, select the DeepSeek model and you’ll be ready to go.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-01/deepseek-main-page.png?sfvrsn=c2434b71_2" class="kg-image" alt="deepseek main page" loading="lazy" width="975" height="607"></figure><p>Let’s try it out with a query. For me, I entered an oddly specific and purely hypothetical query—how can a tired parent persuade his daughter to expand musical tastes beyond just Taylor Swift? (Just saying: the inevitable Kelce/Swift wedding will probably be financed by all my Spotify listens.)</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-01/deepseek-thinking.png?sfvrsn=e78804ac_2" class="kg-image" alt="deepseek thinking" loading="lazy" width="1042" height="485"></figure><p>You’ll notice right away something you don’t see with many other models: It’s walking you through its thought process before sending an answer. Look for this feature to be quickly “borrowed” by its competitors.</p><p>After a minute or two, I’ll have an answer from DeepSeek.</p><figure class="kg-card kg-image-card"><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-01/taylor-answers.png?sfvrsn=67d76cfa_2" class="kg-image" alt="taylor answers" loading="lazy" width="995" height="672"></figure><h2 id="next-steps">Next Steps</h2><p>With DeepSeek set up in your local environment, the world is yours. Check out&nbsp;<a href="https://www.youtube.com/live/p2nvP0Y-cuI?ref=daveabrock.com">Ed’s DeepSeek AI with .NET Aspire demo</a>&nbsp;to learn more about integrating it and any potential drawbacks.</p><p>See also:</p><ul><li><a href="https://www.youtube.com/watch?v=KMMzCjbeNdg&ref=daveabrock.com">Running DeepSeek locally with Just a Browser</a>&nbsp;live stream with Ed Charbeneau</li><li><a href="https://www.telerik.com/blogs/local-genai-processing-implementing-webllm-blazor-webassembly?ref=daveabrock.com">Local GenAI Processing: WebLLM with Blazor WebAssembly</a>&nbsp;blog post by Ed</li></ul><p>Any thoughts on DeepSeek, AI or this article? Feel free to leave a comment. Happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Build 2022 Updates for ASP.NET Core Developers ]]></title>
        <description><![CDATA[ This post was originally published on the Telerik Developer Blog.

Build 2022 took place last week, giving Microsoft developers a lot to get excited about—whether it’s new Azure bells and whistles, Windows development, developer productivity updates, or tons of other content you can view from the session list. ]]></description>
        <link>https://www.daveabrock.com/2022/06/03/build-2022-updates-for-asp-net-core-developers/</link>
        <guid isPermaLink="false">68f688ee0ac93000018c8170</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 03 Jun 2022 00:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1677442135703-1787eea5ce01?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;M3wxMTc3M3wwfDF8c2VhcmNofDR8fGFpfGVufDB8fHx8MTc2MDk4ODcxNXww&amp;ixlib&#x3D;rb-4.1.0&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <blockquote>This post was originally published on the <a href="https://www.telerik.com/blogs/build-2022-updates-aspnet-core-developers?ref=daveabrock.com" rel="noreferrer">Telerik Developer Blog</a>.</blockquote><p>Build 2022 took place last week, giving Microsoft developers a lot to get excited about—whether it’s new Azure bells and whistles, Windows development, developer productivity updates, or tons of other content you can view from the&nbsp;<a href="https://mybuild.microsoft.com/?ref=daveabrock.com">session list</a>.</p><p>In this article, I’d like to recap three talks that highlighted what’s new in the .NET world—specifically for ASP.NET Core web applications.</p><ul><li>C# 11 Updates</li><li>Output caching in ASP.NET Core 7</li><li>Minimal API updates</li></ul><p><strong>Note:</strong>&nbsp;This post includes code samples. The samples are subject to minor syntax changes before .NET 7 releases in November 2022.</p><h2 id="c-11-updates">C# 11 Updates</h2><p>With .NET pivoting to annual November releases the last few years, the languages are also following suit. With C# 11 development in full swing, Build is always a good time to get a preview of what’s coming. With that in mind, Mads Torgersen led the session,&nbsp;<a href="https://www.youtube.com/watch?v=ChAu226eUNo&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=7&ref=daveabrock.com"><em>What’s Next in C# 11</em></a>, to give us a preview of some new features.</p><p>Here are a few of them:</p><ul><li>Static abstract members</li><li>Pattern matching updates support list patterns</li><li>Required properties</li><li>Raw string literals</li></ul><h3 id="static-abstract-members">Static Abstract Members</h3><p>C# 11 will include the ability to add static abstract members in interfaces, where you can include static properties, overloadable operators or other static members. A big use case is with using mathematical operators, and Mads showed off an example.</p><p>Imagine you’ve got a quick program that adds all items in a given array and it returns the total (for brevity, this uses&nbsp;<a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/top-level-statements?ref=daveabrock.com">top-level statements</a>, which eliminates the need for a&nbsp;<code>Main</code>&nbsp;method):</p><pre><code class="language-csharp">var result = AddAll(new[] { 1, 2, 3, 4, 5 });
Console.WriteLine(result);

int AddAll(int[] values)
{
    int result = 0;

    foreach (var value in values)
    {
        result += value;
    }
    return result;
}
</code></pre><p>What if we could have numeric types implement interfaces? That’s what we can do with static abstract members with this modified&nbsp;<code>AddAll</code>&nbsp;method:</p><pre><code class="language-csharp">T AddAll&lt;T&gt;(T[] values) where T : INumber&lt;T&gt;
{
    T result = T.AdditiveIdentity;

    foreach (var value in values)
    {
        result += value;
    }
    return result;
}
</code></pre><p>Now, we are taking&nbsp;<code>T</code>, which is any type that implements the&nbsp;<code>INumber&lt;TSelf&gt;</code>&nbsp;interface (<code>int</code>,&nbsp;<code>short</code>,&nbsp;<code>long</code>,&nbsp;<code>float</code>,&nbsp;<code>decimal</code>&nbsp;or any type that represents a number). The interface provides access to APIs like&nbsp;<code>Abs</code>,&nbsp;<code>Min</code>,&nbsp;<code>Max</code>,&nbsp;<code>TryParse</code>&nbsp;and the typical mathematical operators, which in turn allows developers to write code that relies on the interfaces with these abstract members as a constraint.</p><p>If you would change the&nbsp;<code>result</code>&nbsp;array to a mix of&nbsp;<code>int</code>&nbsp;and&nbsp;<code>decimal</code>&nbsp;types, it would calculate correctly without having to explicitly declare the specific type, through the beauty of interfaces. For more details on static abstract interfaces check out&nbsp;<a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-abstract-interface-methods?ref=daveabrock.com#static-abstract-interface-methods">the Microsoft documentation</a>.</p><h3 id="pattern-matching-updates-support-list-patterns">Pattern Matching Updates Support List Patterns</h3><p>Using the same example that Mads provided, C# 11 provides updates to pattern matching that helps with processing incoming list items. It can greatly simplify things, like in the following example:</p><pre><code class="language-csharp">T AddAll&lt;T&gt;(T[] values) where T : INumber&lt;T&gt; =&gt; values switch
{
    [] =&gt; T.AdditiveIdentity,
    [var t1, .. var middle] =&gt; t1 + AddAll(middle),
};
</code></pre><h3 id="required-properties">Required Properties</h3><p>Mads also demonstrated something we’ve all been impatiently waiting for: required properties. To illustrate the benefits, let’s build out a trusty&nbsp;<code>Person</code>&nbsp;class:</p><pre><code class="language-csharp">public class Person 
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
}
</code></pre><p>To enforce instantiating certain fields, you would need to rely on a constructor-based approach. If you want to enforce a caller to instantiate a&nbsp;<code>FirstName</code>&nbsp;and&nbsp;<code>LastName</code>, there’s not a way to do it with object initialization. For example, what if a developer writes code before their morning coffee and accidentally makes the&nbsp;<code>LastName</code>&nbsp;the&nbsp;<code>MiddleName</code>?</p><pre><code class="language-csharp">var person = new Person()
{
    FirstName = "Saul",
    MiddleName = "Goodman"
};
</code></pre><p>With required properties, we can enforce this using object initialization, like so:</p><pre><code class="language-csharp">public class Person 
{
    public required string FirstName { get; set; }
    public string MiddleName { get; set; }
    public required string LastName { get; set; }
}
</code></pre><p>In this case, the compiler will throw an error when&nbsp;<code>LastName</code>&nbsp;is not initialized.</p><p>I’m tremendously excited for this feature—it was originally slated for C# 10, and is finally here. It really should have been shipped with the nullability features in the past few releases, as developers have used hacky workarounds like&nbsp;<code>= null!</code>&nbsp;to accommodate these situations. With this update, who needs constructors? Not me.</p><h3 id="raw-string-literals">Raw String Literals</h3><p>Mads also showed off&nbsp;<a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/?ref=daveabrock.com#raw-string-literals">raw string literals</a>. We’ve all dealt with the pain of escaping pesky characters inside our strings, like quotes, double quotes, white space and backslashes. With C# 11, it’s much easier to create multi-line strings, or characters that previously required you to escape them.</p><p>According to the documentation, raw string literals:</p><ul><li>Start and end with a sequence of at least three double quote characters ("""). You can also include more than three consecutive characters to support strings that contain three or more repeated quotes characters.</li><li>Single-line raw string literals require the opening and closing quote characters on the same line and multi-line raw string literals require both opening and closing quote characters on their own line.</li><li>In multi-line raw string literals, any white space to the left of the closing quotes is removed.</li></ul><p>Here’s a simple example—note that string interpolation is also supported:</p><pre><code class="language-csharp">var author = "Andy Dwyer";  
string longMessage = $"""  
"Leslie, I typed your symptoms  
into this thing here and  
it says you have 'internet  
'connectivity problems.'"  
  
— {author}  
""";  
  
Console.WriteLine(longMessage);  
</code></pre><p>The value is immediate when working with JSON or XML-like structures, like this:</p><pre><code class="language-csharp">string html = """
           &lt;body style="normal"&gt;
              &lt;div class="book-content"&gt;
               This is information about the "C# 11" book.
           &lt;/body&gt;
           &lt;footer&gt;
               This is information about the author of the "C# 11" book.
           &lt;/footer&gt;
       &lt;/element&gt;
       """;
</code></pre><h2 id="output-caching-middleware-in-aspnet-core-7">Output Caching Middleware in ASP.NET Core 7</h2><p>In his session,&nbsp;<a href="https://www.youtube.com/watch?v=RYw2pyG74YM&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=5&ref=daveabrock.com"><em>Output Caching in ASP.NET Core 7</em></a>, Sebastian Ros talked about new middleware for caching endpoints.</p><p>If you aren’t familiar, ASP.NET Core already has&nbsp;<a href="https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-6.0&ref=daveabrock.com">response caching middleware</a>&nbsp;that enables developers to enable caching sever responses based on HTTP cache headers. This has limited value for UI apps like Blazor and Razor Pages, as browsers often set request headers to prevent caching. Also, the response caching middleware has limited customization options.</p><p>The new output caching middleware will allow ASP.NET Core developers to:</p><ul><li>Store the results in a web application instead of executing it repeatedly, providing performance benefits</li><li>Configure caching without having to think about HTTP headers</li><li>Storage options (like saving to disk or Azure Storage)</li><li>Use tags to invalidate cache entries</li><li>Have resource locking enabled by default</li></ul><p>You’ll be able to use this through a variety of ASP.NET Core web apps, but let’s see how it works using a Minimal API. To start, let’s cache the root endpoint. To tweak Sebastian’s example ever so slightly, let’s say we’ve got a lawn care shop called Mandy’s Mowers, where we fetch details of the lawn mowers for sale.</p><pre><code class="language-csharp">using Microsoft.AspNetCore.OutputCaching;
using Microsoft.AspNetCore.OutputCaching.Policies;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOutputCaching();

var app = builder.Build();

app.UseOutputCaching();
app.MapGet("/", MowerInventory.GetMowers).OutputCache();
await app.RunAsync();
</code></pre><p>If I want to disable caching for an endpoint, I would do this:</p><pre><code class="language-csharp">app.MapGet("/nocache", MowerInventory.GetMowers).OutputCache(cache =&gt; cache.NoStore());
</code></pre><p>If I want to enable caching for all endpoints, I can add a policy to the configuration.</p><pre><code class="language-csharp">builder.Services.AddOutputCaching(options =&gt;
{
  options.Policies.Add(new OutputCachingPolicy());
});
</code></pre><p>You can also assign policies to specific endpoints. Let’s say I want to cache product detail results pages for just 15 seconds:</p><pre><code class="language-csharp">builder.Services.AddOutputCaching(options =&gt;
{
  options.Policies.Add(new OutputCachingPolicy());
  options.Profiles["QuickCache"] = new OutputCachePolicyBuilder().Expires(TimeSpan.FromSeconds(15)).Build();
});

// other code omitted for brevity

app.MapGet("/results", MowerInventory.GetMowers).OutputCache(cache =&gt; cache.Profile("QuickCache"));
</code></pre><p>If you want to cache by query string value, you can do that too. Consider this endpoint where a user filters by type and color.</p><p><a href="https://mandysmowers.com/results?type=push&color=red&ref=daveabrock.com" rel="nofollow"><code>https://mandysmowers.com/results?type=push&amp;color=red</code></a></p><p>If I wanted to only specify a caching policy by color, I can use the&nbsp;<code>VaryByQuery</code>&nbsp;API:</p><pre><code class="language-csharp">app.MapGet("/results", MowerInventory.GetMowers).OutputCache(p =&gt; p.VaryByQuery("color"));
</code></pre><p>Of course, you can also work with nested endpoints, too. A common scenario would be pages for getting all mowers, and also displaying a specific one.</p><p>We’d first set up a policy:</p><pre><code class="language-csharp">builder.Services.AddOutputCaching(options =&gt;
{
    options.Policies.Add(new OutputCachingPolicy());
    options.Policies.Add(new OutputCachePolicyBuilder().Path("/mowers").Tag("mowers").Build());
});
</code></pre><p>Then, apply a tag to the endpoints:</p><pre><code class="language-csharp">app.MapGet("/mowers", MowerInventory.GetMowers).OutputCache(cache =&gt; cache.Tag("mowers"));
app.MapGet("/mowers/{id}", MowerInventory.GetMowers).OutputCache(cache =&gt; cache.Tag("mowers"));
</code></pre><p>Then, you could perform actions on a tag in a single action, like with performing cache eviction. As shown in the talk, you could build a&nbsp;<code>/purge</code>&nbsp;endpoint to do this:</p><pre><code class="language-csharp">app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag))
{
    await cache.EvictByTagAsync(tag);
};
</code></pre><p>There’s a lot more to come to this exciting feature, and you can&nbsp;<a href="https://github.com/dotnet/aspnetcore/issues/40232?ref=daveabrock.com">follow it on GitHub</a>.</p><h2 id="minimal-api-updates">Minimal API Updates</h2><p>In Stephen Halter and Safia Abdalla’s talk,&nbsp;<a href="https://www.youtube.com/watch?v=PJzWsQ0y-X4&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=4&ref=daveabrock.com"><em>Minimal APIs: Past Present and Future</em></a>, they discussed how Minimal APIs have evolved and what’s in store for .NET 7.</p><p>If you aren’t familiar with Minimal APIs, you use them to create HTTP APIs with minimal dependencies and overhead without the bloat that often comes with ASP.NET Core MVC. (Of course, MVC is going nowhere and it’s up to you to determine what best fits your use case.)</p><p>I initially wrote about&nbsp;<a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com">Minimal APIs in their early days</a>&nbsp;and also&nbsp;<a href="https://www.telerik.com/blogs/dotnet-6-arrived-here-few-my-favorite-things?ref=daveabrock.com">wrote about their capabilities with .NET 6</a>. As discussed in the talk, .NET 6 was when Minimal APIs truly arrived, taking advantage of top-level statements, lambdas and method groups, attributes on lambdas, new&nbsp;<code>Map</code>&nbsp;methods, and more. Looking forward to .NET 7, here are some of my favorites.</p><h3 id="endpoint-filters">Endpoint Filters</h3><p>With .NET 7, Minimal APIs will support endpoint filters, which allow you to inspect and modify input parameters before executing a route handler. This will allow developers to intercept a request, much like in an MVC controller, and perform logic based on the parameters.</p><p>This involves a new&nbsp;<code>IRouteHandlerFilter</code>&nbsp;interface&nbsp;<a href="https://github.com/dotnet/aspnetcore/issues/40506?ref=daveabrock.com">that takes a<u>&nbsp;</u><code>RouteHandlerFilterContext</code></a>&nbsp;which developers can implement for custom filters. The&nbsp;<code>RouteHandlerFilterContext</code>&nbsp;contains&nbsp;<code>HttpContext</code>&nbsp;and&nbsp;<code>Parameters</code>&nbsp;properties—the&nbsp;<code>Parameters</code>&nbsp;is an&nbsp;<code>IList</code>&nbsp;so developers can perform updates on the fly.</p><h3 id="route-groups">Route Groups</h3><p>.NET 7 also ships&nbsp;<a href="https://github.com/dotnet/aspnetcore/issues/36007?ref=daveabrock.com">route groups</a>&nbsp;that allow you to define a single route prefix for a group of endpoints, which allow a variety of&nbsp;<code>IEndpointConventionBuilder</code>&nbsp;extension methods (like&nbsp;<code>RequireCors</code>&nbsp;and&nbsp;<code>RequireAuthorization</code>). You can say goodbye to manually adding authorization to single endpoints. It also allows nesting.</p><h3 id="typed-results">Typed Results</h3><p>With .NET 7 Preview 4,&nbsp;<a href="https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-preview-4/?ref=daveabrock.com#typed-results-for-minimal-apis">typed results</a>&nbsp;should make working with and testing route handlers simpler and easier. To borrow from the talk, here’s a quick example.</p><p>In .NET 6, here’s how you could return a specific response based on if a record with a specific type is found:</p><pre><code class="language-csharp">app.MapGet("/todo/{id}", async (int id, ToDoDb db) =&gt;
    await db.Todos.FindAsync(id) is Todo todo
        ? Results.Ok(todo)
        : Results.NotFound());
</code></pre><p>And here’s how it looks with typed results in .NET 7:</p><pre><code class="language-csharp">app.MapGet("/todo/{id}", async Task&lt;Results&lt;Ok&lt;Todo&gt;, NotFound&gt;&gt; (int id, ToDoDb db) =&gt;
    await db.Todos.FindAsync(id) is Todo todo;
</code></pre><p>This makes testing a lot easier, as this example shows:</p><pre><code class="language-csharp">[Fact]
public async Task GetAllTodos_ReturnsOk()
{
    var db = CreateDbContext();
    var result = await TodosApi.GetAllTodos(db);
    Assert.IsType&lt;Ok&lt;object&gt;&gt;(result);
}
</code></pre><h2 id="wrap-up">Wrap-up</h2><p>I’ve only scratched the surface on all the great .NET web content from Build 2022. The .NET team put together a YouTube playlist of&nbsp;<a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&ref=daveabrock.com">.NET Build content</a>, and you can also&nbsp;<a href="https://www.youtube.com/watch?v=4PxfljMOtlQ&list=PLlrxD0HtieHgklVIx9te6NxMeltNfyPIE&ref=daveabrock.com">check out all 389 on-demand sessions</a>. Here are a few other talks I loved but didn’t have space to address:</p><ul><li><a href="https://www.youtube.com/watch?v=-4BelRbFOVo&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=3&ref=daveabrock.com">Next Steps for Distributed Programming with .NET and Orleans</a></li><li><a href="https://www.youtube.com/watch?v=s48vzy4sC0k&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=10&ref=daveabrock.com">.NET MAUI - Updates and Roadmap</a></li><li><a href="https://www.youtube.com/watch?v=3tdn0aQ6Z5Y&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=11&ref=daveabrock.com">Visual Studio 2022 and Beyond</a></li><li><a href="https://www.youtube.com/watch?v=A0vz_BWxIMc&list=PLdo4fOcmZ0oWEkTI5aWupn_iL_eGJKSqk&index=12&ref=daveabrock.com">Future Possibilities for .NET Core and WASI (WebAssembly on the Server)</a></li></ul><p>Stay tuned, as we’ll cover many of these topics as we get closer to the .NET 7 release in November. Happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Don&#x27;t Do That, Do This: The .NET 6 Edition ]]></title>
        <description><![CDATA[ In this C# Advent post, we have a little fun and talk about some nice, lesser hyped .NET 6 features that might make you happy. ]]></description>
        <link>https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/</link>
        <guid isPermaLink="false">61ae9a6cfa774b003b53bd81</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 08 Dec 2021 08:28:47 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1608096299230-81c7b43d5dfc?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDYwfHxjaHJpc3RtYXN8ZW58MHx8fHwxNjM4OTcyNzI5&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post is my annual contribution to the </em><a href="https://www.csadvent.christmas/?ref=daveabrock.com"><em>2021 C# Advent Calendar</em></a><em>. Please check out all the great posts from our wonderful community!</em></p><p>Have you heard? .NET 6 <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6/?ref=daveabrock.com">has officially arrived</a>. There's a lot of good stuff: C# 10, performance improvements, Hot Reload, Minimal APIs, and much more. As is the case for most releases, a few big features tend to get most of the hype. </p><p>What about the features and improvements that don't knock <em>both </em>your socks off but also help to make your daily development experience more productive? A lot of these "quality of life" features in .NET 6 can help by removing boilerplate and pain and can help you get to the point: shipping quality software.</p><p>As I get into the holiday spirit, consider this a stocking of sorts: just some random, little things that I hope you'll find enjoyable. (And despite the catchy title, there are always tradeoffs: do what works for you.)</p><h2 id="dont-chunk-large-collections-manually-use-the-new-linq-api-instead">Don't chunk large collections manually, use the new LINQ API instead</h2><p>When working with large collections of data, you likely need to work with smaller "chunks" of it—a big use case would be if you're getting a lot of data back from a third-party API. If there's no pagination set up and you have a bunch of data in memory, you'll probably want a way to "page" or split up the data.</p><p>What's a .NET developer to do? Do things the hard way. You'd probably do some logic to set a page size, check what page you're on and if there are any elements left, then update your code when you add pages to a collection. It'd be a series of <code>Take</code> and <code>Skip</code> LINQ calls, or maybe even an extension method, like <a href="https://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq/438513?ref=daveabrock.com#438513">this one that's popular on Stack Overflow</a>:</p><pre><code class="language-csharp">static class LinqExtensions
{
    public static IEnumerable&lt;IEnumerable&lt;T&gt;&gt; Split&lt;T&gt;(this IEnumerable&lt;T&gt; list, int parts)
    {
        int i = 0;
        var splits = from item in list
                     group item by i++ % parts into part
                     select part.AsEnumerable();
        return splits;
    }
}</code></pre><p>Don't do that, do this: use the new LINQ <code>Chunk</code> API. When we call <code>Chunk</code> on 200 elements, we'll get 20 lists of 10 elements each.</p><pre><code class="language-csharp">int pageSize = 10;
IEnumerable&lt;Employee[]&gt; employeeChunk = employees.Chunk(pageSize);</code></pre><h2 id="if-you-need-just-a-date-dont-use-datetime-use-dateonly">If you need just a date, don't use DateTime, use DateOnly</h2><p>If you want to work with dates and times in .NET, you typically start with <code>DateTime</code>, <code>TimeSpan</code>, or <code>DateTimeOffset</code>. What if you only need to work with dates and only need a year, month, or day? In .NET 6, you can use a new <code>DateOnly</code> struct. (You can also use <code>TimeOnly</code>. I also promise this isn't the <a href="https://www.farmersonly.com/?ref=daveabrock.com">start of a dating app</a>.)</p><p>We've all done something like this:</p><pre><code class="language-csharp">var someDateTime = new DateTime(2014, 8, 24);
var justTheDate = someDateTime.ToShortDateString();

Console.WriteLine(someDateTime); // 8/24/2014 12:00:00 AM
Console.WriteLine(justTheDate); // "8/24/2014"</code></pre><p>Don't do that, do this: use the <code>DateOnly</code> struct.</p><pre><code class="language-csharp">var someDateTime = new DateOnly(2014, 8, 24);
Console.WriteLine(someDateTime); // 8/24/2014</code></pre><p>There's <a href="https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/?ref=daveabrock.com">a lot more you can do with these</a>, obviously, in terms of manipulation, calculation days between dates, and even combining with <code>DateTime</code>. Apart from being easier to work with, it also offers better type safety for just dates, a <code>Kind</code> property, and simpler serialization.</p><h2 id="dont-wire-up-a-lot-of-custom-code-for-logging-http-requests-use-the-new-logging-middleware">Don't wire up a lot of custom code for logging HTTP requests, use the new logging middleware</h2><p>Before .NET 6, logging HTTP requests wasn't hard but a little cumbersome. Here's one way: you'd probably have logic to read the request body, use your expert knowledge of ASP.NET Core middleware to pass the stream to whatever is next on the pipeline, and remember to register your middleware—all for a very common activity for any reasonably complex web application.</p><p>Don't do that, do this: use the new .NET 6 <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0&ref=daveabrock.com">HTTP Logging middleware</a> to make your life easier.</p><p>Add this to your project's middleware:</p><pre><code class="language-csharp">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpLogging();

    // other stuff here, removed for brevity
}</code></pre><p>Then, customize the logger as you see fit.</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpLogging(logging =&gt;
    {
        logging.LoggingFields = HttpLoggingFields.All;
        logging.RequestHeaders.Add("X-Request-Header");
        logging.ResponseHeaders.Add("X-Response-Header");
        logging.RequestBodyLogLimit = 4096;
        logging.ResponseBodyLogLimit = 4096;
    });
}</code></pre><p>You'll want to be watchful of what you log and how often you log it, but it's a great improvement.</p><h2 id="dont-use-hacks-to-handle-fatal-blazor-server-exceptions-use-the-errorboundary-component">Don't use hacks to handle fatal Blazor Server exceptions, use the ErrorBoundary component</h2><p>What happens when an unhandled exception in Blazor Server occurs? It's treated as fatal because "<a href="https://github.com/dotnet/aspnetcore/issues/30940?ref=daveabrock.com#issue-831895900">the circuit is left in an undefined state which could lead to stability or security problems in Blazor Server</a>." As a result, you might need to throw try/catch blocks all over the place as a preventive measure or encapsulate logic in JavaScript since no C# code runs after the unhandled exception.</p><p>Don't do that, do this: <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/handle-errors?view=aspnetcore-6.0&ref=daveabrock.com">use the new <code>ErrorBoundary</code> component</a>. It isn't a global exception handler but will help deal with unpredictable behavior, especially with components you don't and can't control.</p><p>You can <a href="https://www.telerik.com/blogs/work-unhandled-exceptions-gracefully-blazor-server-dotnet-6-error-boundaries?ref=daveabrock.com">see my article</a> for the full treatment, but here's the gist: I can add an <code>ErrorBoundary</code> around the <code>@Body</code> of my default layout.</p><pre><code class="language-html">&lt;div class="main"&gt;
    &lt;div class="content px-4"&gt;
        &lt;ErrorBoundary&gt;
            @Body
        &lt;/ErrorBoundary&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>Of course, you probably want to go further than a catch-all boundary. Here's me iterating through a list:</p><pre><code class="language-html">&lt;tbody&gt;
    @foreach (var employee in Employees)
    {
        &lt;ErrorBoundary @key="@board"&gt;
            &lt;ChildContent&gt;
                &lt;tr&gt;
                    &lt;td&gt;@employee.Id&lt;/td&gt;
                    &lt;td&gt;@employee.FirstName&lt;/td&gt;
                    &lt;td&gt;@employee.LastName&lt;/td&gt;
                 &lt;/tr&gt;
            &lt;/ChildContent&gt;
            &lt;ErrorContent&gt;
                Sorry, I can't show @employee.Id because of an internal error.
            &lt;/ErrorContent&gt;
        &lt;/ErrorBoundary&gt;
    }
&lt;/tbody&gt;</code></pre><h2 id="dont-use-serverkestrel-verbose-logging-for-just-a-few-things-use-the-new-subcategories">Don't use Server.Kestrel verbose logging for just a few things, use the new subcategories</h2><p>If I want to enable verbose logging for Kestrel, I'd previously need to use <code>Microsoft.AspNetCore.Server.Kestrel</code>. That still exists, but there are also <a href="https://github.com/dotnet/aspnetcore/issues/30301?ref=daveabrock.com">new subcategories</a> that should make things less expensive. (Computationally; you're still on the hook for holiday gifts, sorry.)</p><p>In addition to <code>Server.Kestrel</code>, we now have <code>Kestrel.BadRequests</code>, <code>Kestrel.Connections</code>, <code>Kestrel.Http2</code>, and <code>Kestrel.Http3</code>.</p><p>Let's say you only want to log bad requests. You'd normally do this:</p><pre><code class="language-json">{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Server.Kestrel": "Debug"
    }
  }
}</code></pre><p>Don't do that. Do this:</p><pre><code class="language-json">{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Server.Kestrel.BadRequests": "Debug"
    }
  }
}</code></pre><p>Is it the sexiest thing you'll read today? Unless you love logging more than I thought you did, probably not. But it'll definitely make working with Kestrel verbose logging much easier.</p><h2 id="dont-get-lost-in-brackets-use-c-10-file-scoped-namespaces-instead">Don't get lost in brackets, use C# 10 file-scoped namespaces instead </h2><p>C# 10 introduces the concept of <a href="https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/">file-scoped namespaces</a>.</p><p>Here's a typical use of namespaces in C#:</p><pre><code class="language-csharp">namespace SuperheroApp.Models
{
   public class Superhero
   {
      public string? FirstName { get; set; }
      public string? LastName { get; set; }
   }
}</code></pre><p>Instead of downloading a bracket colorizer extension, do this instead:</p><pre><code class="language-csharp">namespace SuperheroApp.Models;

public class Superhero
{
   public string? FirstName { get; set; }
   public string? LastName { get; set; }
}
</code></pre><p>Also, for the record (ha!), you can make this even simpler if you want to take advantage of <a href="https://www.daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records/">immutability and value-like behavior</a>:</p><pre><code class="language-csharp">namespace SuperheroApp.Models;

public record Superhero(string? FirstName, string? LastName);</code></pre><p>You should be aware of what you're getting with <a href="https://www.daveabrock.com/2020/11/02/csharp-9-records-immutable-default/">positional parameters</a>, but we can all agree this isn't your grandma's C# (and I'm here for <em>all </em>of it, my apologies to grandma). </p><h3 id="speaking-of-brackets">Speaking of brackets ...</h3><p>Since we're on the topic of brackets, C# 10 also introduces <a href="https://www.daveabrock.com/2021/11/18/exploring-c-10-use-extended-property-patterns-to-easily-access-nested-properties/">e<a href="https://www.daveabrock.com/2021/11/18/exploring-c-10-use-extended-property-patterns-to-easily-access-nested-properties/">xtended property patterns</a></a>.</p><p>You could use property patterns in a switch expression like this:</p><pre><code class="language-csharp">public static int CalculateSuitSurcharge(Superhero hero) =&gt;

        hero switch
        {
            { Suit: { Color: "Blue" } } =&gt; 100,
            { Suit: { Color: "Yellow" } } =&gt; 200,
            { Suit: { Color: "Red" } } =&gt; 300
            _ =&gt; 0
        };</code></pre><p>Don't do that. Do this:</p><pre><code class="language-csharp">public static int CalculateSuitSurcharge(Superhero hero) =&gt;

        hero switch
        {
            { Suit.Color: "Blue" } =&gt; 100,
            { Suit.Color: "Yellow" } =&gt; 200,
            { Suit.Color: "Red" } =&gt; 300
            _ =&gt; 0
        };</code></pre><h2 id="wrapping-up">Wrapping up</h2><p>I hope you enjoyed this post, and you learned a thing or two about how .NET 6 can make your developer life just a little bit easier. Have you tried any of these? Do you have others to share? Let me know in the comments <a href="https://twitter.com/daveabrock?ref=daveabrock.com">or on Twitter</a>.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ .NET 6 Has Arrived: Here Are A Few of My Favorite Things ]]></title>
        <description><![CDATA[ I talk about my favorite things about .NET 6: Hot Reload, Minimal APIs, HTTP logging, Blazor improvements, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/12/03/dotnet-6-favorite-things/</link>
        <guid isPermaLink="false">6195a9dd09e937003bbf0cbe</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 03 Dec 2021 06:59:58 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1454486837617-ce8e1ba5ebfe?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDEyfHxoYXBweXxlbnwwfHx8fDE2Mzg1MzYzNzc&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post was originally published on the <a href="https://www.telerik.com/blogs/dotnet-6-arrived-here-few-my-favorite-things?ref=daveabrock.com">Telerik Developer Blog</a>.</em></p><p>For the second straight November, .NET developers have received an early holiday gift: <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6/?ref=daveabrock.com">a new release of the .NET platform</a>. Last month, Microsoft made .NET 6 generally available—and <a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oVFtp9MDEBNbA2sSqYvXSXO&ref=daveabrock.com">hosted a virtual conference</a> to celebrate its new features.</p><p>What were the goals of .NET 6? If you look at <em><a href="https://themesof.net/query?ref=daveabrock.com">themesof.net</a></em>, you can quickly see the themes of the .NET 6 release, which include some of the following:</p><ul><li>Appeal to net-new devs, students, and new technologists</li><li>Improve startup and throughput using runtime exception information</li><li>The client app development experience</li><li>Recognized as a compelling framework for cloud-native apps</li><li>Improve inner-loop performance for .NET developers</li></ul><p>We could spend the next ten blog posts writing about all the new .NET 6 improvements and features. I'd love to do that, but I haven't even <em>started </em>shopping for the holidays. Instead, I'd like to show off some of my favorite things that I'll be using on my .NET 6 projects. Most of these changes revolve around <a href="https://devblogs.microsoft.com/dotnet/announcing-asp-net-core-in-net-6/?ref=daveabrock.com">web development in ASP.NET Core 6</a> since this site focuses on those topics.</p><h2 id="hot-reload">Hot Reload</h2><p>Way <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">back in April</a>, I wrote here about the Hot Reload capability in .NET 6. We've come a long way since then, but I felt the same as I do now: this is the biggest boost to a .NET web developer's productivity over the last few years. If you aren't familiar with Hot Reload, let's quickly recap.</p><p>The idea of "hot reload" has been around for quite a few years: you save a file, and the change appears almost instantaneously. Once you work with hot reloading, it's tough to go back. As the .NET team tries to attract outsiders and new developers, not having this feature can be a non-starter to outsiders: it's table stakes for many developers. The concept is quite popular in the front-end space and .NET developers have been asking for this for a while. (Admittedly, introducing hot reload to a statically typed language is much more complex than doing it for a traditionally interpreted language like JavaScript.)</p><p>With .NET 6, you can use Hot Reload to make changes to your app without needing to restart or rebuild it. Hot Reload doesn't just work with static content, either—it works with most C# use cases and also preserves the state of your application as well—but you'll want to hit up the Microsoft Docs to learn about <a href="https://docs.microsoft.com/en-us/visualstudio/debugger/supported-code-changes-csharp?view=vs-2022&ref=daveabrock.com">unsupported app scenarios</a>.</p><p>Here's a quick example to show how the application state gets preserved in a Blazor web app. If I'm in the middle of an interaction and I update the <code>currentCount</code> from <code>0</code> to <code>10</code>, will things reset? No! Notice how I can continue increasing the counter, and then my counter starts at 10 when I refresh the page.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/11/hr-preserve-state.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>You can leverage Hot Reload in whatever way you prefer: powerful IDEs like <a href="https://blog.jetbrains.com/dotnet/2021/10/25/hot-reload-for-net-6-in-rider-2021-3/?ref=daveabrock.com">JetBrains Rider</a> and <a href="https://devblogs.microsoft.com/dotnet/update-on-net-hot-reload-progress-and-visual-studio-2022-highlights/?ref=daveabrock.com#improved-user-experience-in-visual-studio-2022">Visual Studio 2022</a> have this capability. You can also utilize it from the command line if you prefer (yes, <a href="https://devblogs.microsoft.com/dotnet/net-hot-reload-support-via-cli/?ref=daveabrock.com">we do</a>). It's important to mention that this works for all ASP.NET Core Web apps.</p><h2 id="minimal-apis">Minimal APIs</h2><p>Have you ever wanted to write simple APIs in ASP.NET Core quickly but felt helpless under the bloat of ASP.NET Core MVC, wishing you could have an <a href="http://expressjs.com/en/starter/hello-world.html?ref=daveabrock.com">Express-like model</a> for writing APIs?</p><p>The ASP.NET team has rolled out minimal APIs—a new, simple way to build small microservices and HTTP APIs in ASP.NET Core. Minimal APIs hook into ASP.NET Core's hosting and routing capabilities and allow you to build fully functioning APIs with just a few lines of code. Minimal APIs do not replace building APIs with MVC—if you are building complex APIs or prefer MVC, you can keep using it as you always have—but it's an excellent approach to writing no-frills APIs. We <a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com">wrote about it in June</a>, but things have evolved <em>a lot</em> since then. Let's write a simple API to show it off.</p><p>First, the basics: thanks to lambdas, top-level statements, and C# 10 global usings, this is all it takes to write a "Hello, Telerik!" API.</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.MapGet("/", () =&gt; "Hello, Telerik!");
app.Run();</code></pre><p>Of course, we'll want to get past the basics. How can I <em>really </em>use it? Using <code>WebApplication</code>, you can add middleware just like you previously would in the <code>Configure</code> method in <code>Startup.cs</code>. In .NET 6, your configuration takes place in Program.cs instead of a separate <code>Startup</code> class.</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.UseResponseCaching(); 
app.UseResponseCompression(); 
app.UseStaticFiles();

// ...

app.Run();</code></pre><p>If you want to do anything substantial, though, you'll want to add services using a <code>WebApplicationBuilder</code> (again, like you typically would previously in the <code>ConfigureServices</code> method in <code>Startup.cs</code>):</p><pre><code class="language-csharp">var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton&lt;MyCoolService&gt;();
builder.Services.AddSingleton&lt;MyReallyCoolService&gt;();

builder.Services.AddSwaggerGen(c =&gt;
{
    c.SwaggerDoc("v1", new() {
        Title = builder.Environment.ApplicationName, Version = "v1" });
});

var app = builder.Build();

// ...

app.Run();</code></pre><p>Putting it all together, let's write a simple CRUD API that works with Entity Framework Core and a <code>DbContext</code>. We'll work with some superheroes because apparently, <a href="https://www.daveabrock.com/2021/10/21/csharp-10-global-usings/">that's what I do</a>. With the help of <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record?ref=daveabrock.com">record types</a>, we can make our data models a little less verbose, too.</p><pre><code class="language-csharp">using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext&lt;SuperheroDb&gt;(o =&gt; o.UseInMemoryDatabase("Superheroes"));

builder.Services.AddSwaggerGen(c =&gt;
{
    c.SwaggerDoc("v1", new() {
        Title = builder.Environment.ApplicationName, Version = "v1" });
});

var app = builder.Build();

app.MapGet("/superheroes", async (SuperheroDb db) =&gt;
{
    await db.Superheroes.ToListAsync();
});

app.MapGet("/superheroes/{id}", async (SuperheroDb db, int id) =&gt;
{
    await db.Superheroes.FindAsync(id) is Superhero superhero ?
    	Results.Ok(superhero) : Results.NotFound();
});

app.MapPost("/superheroes", async (SuperheroDb db, Superhero hero) =&gt;
{
    db.Superheroes.Add(hero);
    await db.SaveChangesAsync();

    return Results.Created($"/superheroes/{hero.Id}", hero);
});

app.MapPut("/superheroes/{id}",
    async (SuperheroDb db, int id, Superhero heroInput) =&gt;
    {
        var hero = await db.Superheroes.FindAsync(id);
        
        if (hero is null)
           return Results.NotFound();

        db.Update(heroInput);
        await db.SaveChangesAsync();

        return Results.NoContent();
    });


app.MapDelete("/superheroes/{id}",
    async (SuperheroDb db, int id) =&gt;
    {
        var hero = await db.Superheroes.FindAsync(id);
        if (hero is null)
            return Results.NotFound();

        db.Superheroes.Remove(hero);
        await db.SaveChangesAsync();
        return Results.Ok();
    });

app.Run();

record Superhero(int Id, string? Name, int maxSpeed);

class SuperheroDb : DbContext
{
    public SuperheroDb(DbContextOptions&lt;SuperheroDb&gt; options)
        : base(options) { }

    public DbSet&lt;Superhero&gt; Todos =&gt; Set&lt;Superhero&gt;();
}</code></pre><p>As you can see, you can <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0&ref=daveabrock.com">do a lot with Minimal APIs</a> while keeping them relatively lightweight. If you want to continue using MVC, that's your call—but with APIs in .NET you no longer have to worry about the overhead of MVC if you don't want it. If you want to learn more, David Fowler has put together a comprehensive document on how to leverage Minimal APIs—it's <a href="https://gist.github.com/davidfowl/ff1addd02d239d2d26f4648a06158727?ref=daveabrock.com">worth checking out</a>. </p><p>Looking at the code sample above, it's easy to wonder if this is all a race to see what we can throw in the <code>Program.cs</code> file and how easy it is to get messy. This can happen in any app: I don't know about you, but I've seen my share of controllers that were rife for abuse. </p><p>It's essential to see the true value of this model—not how cool and sexy it is to write an entire .NET CRUD API in one file, but the ability to write simple APIs with minimal dependencies and exceptional performance. If things look unwieldy, organize your project as you see fit, just like you always have. </p><h2 id="simplified-http-logging">Simplified HTTP logging</h2><p>How often have you used custom middleware, libraries, or solutions to log simple HTTP requests? I've done it more than I'd like to admit. .NET 6 introduces HTTP Logging middleware for ASP.NET Core apps that <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0&ref=daveabrock.com">log information about HTTP requests and responses for you</a>, like: </p><ul><li>Request information</li><li>Properties</li><li>Headers</li><li>Body data</li><li>Response information</li></ul><p>You can also select which logging properties to include, which can help with performance too.</p><p>To get started, add this in your project's middleware:</p><pre><code class="language-csharp">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpLogging();

    // other stuff here, removed for brevity
}</code></pre><p>To customize the logger, you can use <code>AddHttpLogging</code>:</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpLogging(logging =&gt;
    {
        logging.LoggingFields = HttpLoggingFields.All;
        logging.RequestHeaders.Add("X-Request-Header");
        logging.ResponseHeaders.Add("X-Response-Header");
        logging.RequestBodyLogLimit = 4096;
        logging.ResponseBodyLogLimit = 4096;
    });
}</code></pre><p>If we want to pair this with a Minimal API, here's how it would look:</p><pre><code class="language-csharp">using Microsoft.AspNetCore.HttpLogging;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =&gt;
{
    logging.LoggingFields = HttpLoggingFields.All;
    logging.RequestHeaders.Add("X-Request-Header");
    logging.RequestHeaders.Add("X-Response-Header");
    logging.RequestBodyLogLimit = 4096;
    logging.ResponseBodyLogLimit = 4096;
});

var app = builder.Build();
app.UseHttpLogging();

app.MapGet("/", () =&gt; "I just logged the HTTP request!");

app.Run();</code></pre><h2 id="blazor-improvements">Blazor improvements</h2><p>.NET 6 ships with many great updates to <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor?ref=daveabrock.com">Blazor</a>, the client-side UI library that's packaged with ASP.NET Core. I want to discuss my favorite updates: error boundaries, dynamic components, and preserving pre-rendered state. Check out Jon Hilton's great post if you want to learn more about .NET 6 Blazor updates.</p><h3 id="error-boundaries">Error boundaries</h3><p>Blazor error boundaries provide an easy way to handle exceptions within your component hierarchy. When an unhandled exception occurs in Blazor Server, it's treated as a fatal error because the circuit hangs in an undefined state. As a result, your app is as good as dead, it loses its state, and your users are met with an undesirable <em>An unhandled error has occurred</em> message, with a link to reload the page.</p><p>Inspired by error boundaries in React, the <code>ErrorBoundary</code> component attempts to catch recoverable errors that can't permanently corrupt state—and like the React feature, it also renders a fallback UI.</p><p>I can add an <code>ErrorBoundary</code> around the <code>@Body</code> of a Blazor app's default layout, like so.</p><pre><code class="language-html">&lt;div class="main"&gt;
    &lt;div class="content px-4"&gt;
        &lt;ErrorBoundary&gt;
            @Body
        &lt;/ErrorBoundary&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>If I get an unhandled exception, I'll get the default fallback error message.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/11/image-1.png" class="kg-image" alt loading="lazy" width="1830" height="937" srcset="https://www.daveabrock.com/content/images/size/w600/2021/11/image-1.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/11/image-1.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/11/image-1.png 1600w, https://www.daveabrock.com/content/images/2021/11/image-1.png 1830w" sizes="(min-width: 720px) 720px"></figure><p> Of course, you can always customize the UI yourself.</p><pre><code>&lt;ErrorBoundary&gt;
    &lt;ChildContent&gt;
        @Body
    &lt;/ChildContent&gt;
    &lt;ErrorContent&gt;
        &lt;p class="custom-error"&gt;Woah, what happened?&lt;/p&gt;
    &lt;/ErrorContent&gt;
&lt;/ErrorBoundary&gt;</code></pre><p> If you'd like the complete treatment, check out <a href="https://www.telerik.com/blogs/work-unhandled-exceptions-gracefully-blazor-server-dotnet-6-error-boundaries?ref=daveabrock.com">my post from earlier this summer</a>.  It still holds up (even the MAUI Man references).</p><h3 id="dynamic-components">Dynamic components</h3><p>What happens if you want to render your components dynamically when you don't know your types ahead of time? It previously was a pain in Blazor through a custom render tree or declaring a series of <code>RenderFragment</code> components. With .NET 6, you can render a component specified by type. When you bring in the component, you set the <code>Type</code> and optionally a dictionary of <code>Parameters</code>.</p><pre><code class="language-csharp">&lt;DynamicComponent Type="@myType" Parameters="@myParameterDictionary" /&gt;
</code></pre><p>I find dynamic components especially valuable when working with form data—you can render data based on selected values without iterating through a bunch of possible types. If this interests you (or if you like rockets), <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/dynamiccomponent?view=aspnetcore-6.0&ref=daveabrock.com">check out the official documentation</a>.</p><h3 id="preserving-pre-rendered-state">Preserving pre-rendered state</h3><p>Despite all the performance and trimming improvements with Blazor WebAssembly, initial load time remains a consideration. To help with this, you can prerender apps from the server to help with its <em>perceived </em>load time. This means that Blazor can immediately render your app's HTML while it is wiring up its dynamic bits. That's great, but it also previously meant that any state was lost.</p><p>Help has arrived. To persist state, there's a new <code>persist-component-state</code> tag helper that you can utilize:</p><pre><code class="language-html">&lt;component type="typeof(App)" render-mode="ServerPrerendered" /&gt;
&lt;persist-component-state /&gt;</code></pre><p>In your C# code, you can inject <code>PersistComponentState</code> and register an event to retrieve and ultimately persist the objects. On subsequent loads, your <code>OnInitializedAsync</code> method can retrieve data from the persisted state—if it doesn't exist, it'll get the data from your original method (typically a service of some sort).</p><p>To see it in action, check out the <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/persist-component-state?view=aspnetcore-6.0&ref=daveabrock.com">Microsoft documentation</a>.</p><h2 id="c-10-updates">C# 10 updates</h2><p>Along with .NET 6, we've also got a new version of C#—C# 10. It ships with some great new features, like file-scoped namespaces, global usings, lambda improvements, extended property patterns, null argument checks, and much more. Check out <a href="https://www.telerik.com/blogs/what-was-added-csharp-10?ref=daveabrock.com">Joseph Guadagno's blog post for more details</a>, as well as <a href="https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10?ref=daveabrock.com">Microsoft's blog post</a>. </p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use AzCopy to migrate files from AWS S3 to Azure Storage ]]></title>
        <description><![CDATA[ In this post, I talk about my experience using the AzCopy tool to migrate files from Amazon S3 to Azure Storage. ]]></description>
        <link>https://www.daveabrock.com/2021/11/21/use-azcopy-to-migrate-files-from-aws-s3-to-azure-storage/</link>
        <guid isPermaLink="false">61992c9c09e937003bbf0d19</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 21 Nov 2021 10:47:50 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1517430816045-df4b7de11d1d?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGNvcHl8ZW58MHx8fHwxNjM3NDI5MDI1&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>At the risk of upsetting Jeff Bezos, I recently moved a few million PDF files from <a href="https://aws.amazon.com/s3/?ref=daveabrock.com">Amazon S3</a> to Azure Storage (<a href="https://azure.microsoft.com/en-us/services/storage/blobs/?OCID=AID2200277_SEM_13b6ab1f0149198aa0b1ca862c00bac7:G:s&ef_id=13b6ab1f0149198aa0b1ca862c00bac7:G:s&msclkid=13b6ab1f0149198aa0b1ca862c00bac7&ref=daveabrock.com#overview">Blob Storage</a>, in fact). I kept it simple and opted to use Microsoft's <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?ref=daveabrock.com">AzCopy tool</a>. It's a command-line tool that allows you to copy blobs or files from or to an Azure Storage account. AzCopy also integrates <a href="https://azure.microsoft.com/en-us/blog/azcopy-support-in-azure-storage-explorer-now-available-in-public-preview/?ref=daveabrock.com">with the Azure Storage Explorer client application</a>, but using a UI wasn't ideal with the number of files I had. </p><p>In this post, I'd like to show an authorization "gotcha" to keep in mind and a few things I learned that might help you. </p><h2 id="authorize-azcopy-to-access-your-azure-storage-account-and-amazon-s3">Authorize AzCopy to access your Azure Storage account and Amazon S3</h2><p>After you <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#download-azcopy">install AzCopy</a>—the installation is a <em>.zip</em> or <em>.tar</em> file depending on your environment—you'll need to let AzCopy know that you are authorized to access the Amazon S3 and Azure Storage resources. </p><p>From the Azure side, you can elect to use Azure Active Directory (AD) or a SAS token.  For me, I ran <code>azcopy login</code> to log in to Azure with my credentials. If you want to run inside a script or have more advanced use cases, it's a good idea to <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-authorize-azure-active-directory?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#authorize-a-managed-identity">authorize a managed identity</a>.</p><p>With ownership access to the storage account, I thought that was all I needed. Not so fast!</p><p>You will also need <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-authorize-azure-active-directory?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com">one of these permissions in Azure AD</a>:</p><ul><li>Storage Blob Data Reader (downloads only)</li><li>Storage Blob Data Contributor</li><li>Storage Blob Data Owner</li></ul><p><strong>Note</strong>: Even if you are a Storage Account Owner, you <em>still </em>need one of those permissions.</p><p>You'll need to grab an Access Key ID and AWS Secret Access Key from Amazon Web Services. If you're not sure how to retrieve those, <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html?ref=daveabrock.com#Using_CreateAccessKey">check out the AWS docs</a>.</p><p>From there, it's as easy as setting a few environment variables (I'm using Windows):</p><ul><li><code>set AWS_ACCESS_KEY_ID=&lt;my_key&gt;</code></li><li><code>set AWS_SECRET_ACCESS_KEY=&lt;my_secret_key&gt;</code></li></ul><h2 id="copy-an-aws-bucket-directory-to-azure-storage">Copy an AWS bucket directory to Azure Storage</h2><p>I needed to copy all the files from a public AWS directory with the pattern <code>/my-bucket/dir/dir/dir/dir/</code> to a public Azure Storage container. To do that, I called <code>azcopy</code> like so:</p><pre><code class="language-bash">azcopy "https://s3.amazonaws.com/my-bucket/dir/dir/dir/dir/*" "https://mystorageaccount.blob.core.windows.net/mycontainer" --recursive=true</code></pre><p>This command allowed me to take <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-s3?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#copy-a-bucket">anything under the directory</a> while also keeping the file structure from the S3 bucket. I knew that it was all PDF files, but I could have also used the <code>--include-pattern</code> flag like this:</p><pre><code class="language-bash">azcopy "https://s3.amazonaws.com/my-bucket/dir/dir/dir/dir/*" "https://mystorageaccount.blob.core.windows.net/mycontainer" --include-pattern "*.pdf" --recursive=true</code></pre><p>There's a lot of flexibility here—you can specify multiple <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-blobs-upload?ref=daveabrock.com#specify-multiple-complete-file-names">complete file names</a>, <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-blobs-upload?ref=daveabrock.com#use-wildcard-characters">wildcard characters</a> (I could have set multiple file types here), and even based on <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-blobs-upload?ref=daveabrock.com#upload-files-that-were-modified-before-or-after-a-date-and-time">file modified dates</a>. I might need to be more selective in the future, so I was happy to see all the options at my disposal.</p><h2 id="resuming-jobs">Resuming jobs</h2><p>If running AzCopy for a while, you might deal with a stopped job. It could be because of failures or a system reboot. To start where you left off, you can run <code>azcopy jobs list</code> to get a list of your jobs in this format:</p><pre><code>Job Id: &lt;some-guid&gt;
Start Time: &lt;when-the-job-started&gt;
Status: Cancelled | Completed | Failed
Command: copy "source" "destination" --any-flags

</code></pre><p>With the correct job ID in hand, I could run the following command to pick up where I left off:</p><p><code>azcopy jobs resume &lt;job-id&gt;</code></p><p>If you need to get to the bottom of any errors, you can <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-configure?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#change-the-default-log-level">change the default log level</a> (the default is <code>INFO</code>) and <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-configure?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#view-and-resume-jobs">filter by jobs with a <code>Failed</code> state</a>. AzCopy creates log and plan files for every job you run in the <code>%USERPROFILE%\.azcopy</code> directory on Windows.</p><p>After you finish, you can clean up all your plan and log files by executing <code>azcopy jobs clean</code> (or <code>azcopy jobs rm &lt;job-id&gt;</code> if you want to remove just one).</p><h2 id="performance-optimization-tips">Performance optimization tips</h2><p>Microsoft recommends that individual jobs contain no more than 10 million files. Jobs that transfer more than 50 million files can suffer from degraded performance <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#reduce-the-size-of-each-job">because of the tracking overhead</a>. I didn't need to worry about performance, but I still <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com">learned a few valuable things</a>.</p><p>To speed things up, you can increase the number of concurrent requests by setting the <code>AZCOPY_CONCURRENCY_VALUE</code> environment variable. By default, Microsoft sets the value to 16 multiplied by the number of CPUs on your machine—if you have less than 5 CPUs, the value is 16. Because I have 12 CPUs, AzCopy set the <code>AZ_CONCURRENCY_VALUE</code> to 192. </p><p>If you'd like to confirm, you can look at the top of your job's log file.</p><pre><code>2021/11/19 16:39:20 AzcopyVersion  10.13.0
2021/11/19 16:39:20 OS-Environment  windows
2021/11/19 16:39:20 OS-Architecture  amd64
2021/11/19 16:39:20 Log times are in UTC. Local time is 19 Nov 2021 10:39:20
2021/11/19 16:39:20 Job-Command copy https:/mystorageaccount.blob.core.windows.net/my-container --recursive=true 
2021/11/19 16:39:20 Number of CPUs: 12
2021/11/19 16:39:20 Max file buffer RAM 6.000 GB
2021/11/19 16:39:20 Max concurrent network operations: 192 (Based on number of CPUs. Set AZCOPY_CONCURRENCY_VALUE environment variable to override)
2021/11/19 16:39:20 Check CPU usage when dynamically tuning concurrency: true (Based on hard-coded default. Set AZCOPY_TUNE_TO_CPU environment variable to true or false override)
2021/11/19 16:39:20 Max concurrent transfer initiation routines: 64 (Based on hard-coded default. Set AZCOPY_CONCURRENT_FILES environment variable to override)
2021/11/19 16:39:20 Max enumeration routines: 16 (Based on hard-coded default. Set AZCOPY_CONCURRENT_SCAN environment variable to override)
2021/11/19 16:39:20 Parallelize getting file properties (file.Stat): false (Based on AZCOPY_PARALLEL_STAT_FILES environment variable)</code></pre><p>You can tweak these values to see what works for you. Luckily, AzCopy allows you to <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#reduce-the-size-of-each-job">run benchmark tests</a> that will report a recommended concurrency value.</p><h2 id="wrap-up">Wrap up</h2><p>This was my first time using AzCopy for any serious work, and I had a good experience. It comes with a lot more flexibility than I imagined and even has features for <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com">limiting throughput</a> and <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com#optimize-memory-use">optimizing memory use</a>.</p><p>To get started, click the link below to begin using AzCopy—and let me know what you think of it! </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?toc=/azure/storage/blobs/toc.json&ref=daveabrock.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Copy or move data to Azure Storage by using AzCopy v10</div><div class="kg-bookmark-description">AzCopy is a command-line utility that you can use to copy data to, from, or between storage accounts. This article helps you download AzCopy, connect to your storage account, and then transfer files.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt=""><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">normesta</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt=""></div></a></figure> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Exploring C# 10: Use Extended Property Patterns to Easily Access Nested Properties ]]></title>
        <description><![CDATA[ Welcome back to my series on new C# 10 features. So far we&#39;ve talked about 
file-scoped namespaces
[https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/] and 
global using declarations
[https://www.daveabrock.com/2021/10/21/csharp-10-global-usings/]. Today, we&#39;ll
talk about extended property patterns in C# ]]></description>
        <link>https://www.daveabrock.com/2021/11/18/exploring-c-10-use-extended-property-patterns-to-easily-access-nested-properties/</link>
        <guid isPermaLink="false">618a5137630a6c003b44cf2d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 17 Nov 2021 19:34:28 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1439397629354-e2e3dea8f6f0?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fG5lc3R8ZW58MHx8fHwxNjM2NDU0NzE0&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome back to my series on new C# 10 features. So far we've talked about <a href="https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/">file-scoped namespaces</a> and <a href="https://www.daveabrock.com/2021/10/21/csharp-10-global-usings/">global using declarations</a>. Today, we'll talk about extended property patterns in C# 10.</p><p>Over the last few years, C# has made a lot of property pattern enhancements. Starting with C# 8, the language has supported <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8?ref=daveabrock.com#property-patterns">extended property patterns</a>, a way to match an object's specific properties. </p><p>For our example, let's continue the superhero theme with a <code>Person</code>, a <code>Superhero</code> that inherits from <code>Person</code>, and a <code>Suit</code>. We're going to calculate any special surcharges when making a particular superhero's suit.  </p><pre><code class="language-csharp">public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? Address { get; set; }
    public string? City { get; set; }
}

public class Superhero : Person
{
    public int MaxSpeed { get; set; }
    public Suit? Suit { get; set; }
}

public class Suit
{
    public string? Color { get; set; }
    public bool HasCape { get; set; }
    public string WordsToPrint { get; set; }
}</code></pre><p>Now let's create a quick object for Iron Man:</p><pre><code class="language-csharp">var tonyStark = new Superhero()
{
    FirstName = "Tony",
    LastName = "Stark",
    Address = "10880 Malibu Point",
    City = "Malibu",
    Suit = new Suit
    {
       Color = "Red",
       HasCape = false
    }
};</code></pre><p>In our switch expression, let's say we want to determine special pricing based on a particular suit's color.</p><p>Here's how we'd do it in C# 9:</p><pre><code class="language-csharp">public static int CalculateSuitSurcharge(Superhero hero) =&gt;

        hero switch
        {
            { Suit: { Color: "Blue" } } =&gt; 100,
            { Suit: { Color: "Yellow" } } =&gt; 200,
            { Suit: { Color: "Red" } } =&gt; 300
            _ =&gt; 0
        };</code></pre><p>With C# 10, we can use dot notation to make it a bit cleaner:</p><pre><code class="language-csharp">public static int CalculateSuitSurcharge(Superhero hero) =&gt;

        hero switch
        {
            { Suit.Color: "Blue" } =&gt; 100,
            { Suit.Color: "Yellow" } =&gt; 200,
            { Suit.Color: "Red" } =&gt; 300
            _ =&gt; 0
        };</code></pre><p>Much like before, you can also use multiple expressions at once. Let's say we wanted to charge a surcharge for a notoriously difficult customer. Look at how we can combine multiple properties in a single line.</p><pre><code class="language-csharp">public static int CalculateSuitSurcharge(Superhero hero) =&gt;

        hero switch
        {
            { Suit.Color: "Blue" } =&gt; 100,
            { Suit.Color: "Yellow" } =&gt; 200,
            { Suit.Color: "Red", Address: "10880 Malibu Point" }  =&gt; 500,
            { Suit.Color: "Red" } =&gt; 300
            _ =&gt; 0
        };</code></pre><p>That's all there is to it. Will this feature change your life? No. Even so, it's a nice update that allows for cleaner and simpler code. </p><p>There's a lot more you can do with property patterns as well, so I'd recommend hitting up the Microsoft Docs to learn more.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns?ref=daveabrock.com#property-pattern"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Patterns - C# reference</div><div class="kg-bookmark-description">Learn about the patterns supported by C# pattern matching expressions and statements.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt=""><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">BillWagner</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/dotnet/media/logo_csharp.png" alt=""></div></a></figure><p>If you're interested in the design proposal, you can also find it below. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/extended-property-patterns?ref=daveabrock.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Extended property patterns - C# 10.0 draft specifications</div><div class="kg-bookmark-description">This feature specification describes extended property patterns. These enable more convenient syntax to pattern match on properties nested in objects contained in an object.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt=""><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">dotnet-bot</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt=""></div></a></figure><p>Let me know your thoughts below. Happy coding!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Exploring Fiddler Jam: What&#x27;s New? ]]></title>
        <description><![CDATA[ Let’s learn about what’s new with Fiddler Jam—an end-to-end troubleshooting solution that helps users, support and engineering solve problems quickly. ]]></description>
        <link>https://www.daveabrock.com/2021/11/06/exploring-fiddler-jam-whats-new/</link>
        <guid isPermaLink="false">6141d02215458e004b3a6214</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 06 Nov 2021 10:00:42 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1468577760773-139c2f1c335f?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDN8fGphbXxlbnwwfHx8fDE2MzYyMTA1ODg&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post was originally featured on the <a href="https://www.telerik.com/blogs/exploring-fiddler-jam-whats-new?ref=daveabrock.com">Telerik Developer Blog</a>.</em></p><p>In August, <a href="https://www.telerik.com/blogs/exploring-fiddler-jam-get-time-back-solving-issues-faster?ref=daveabrock.com">I introduced you to Fiddler Jam</a>. What is Jam? In short, it’s a solution to help support and development teams troubleshoot remote issues with web applications in a quick, easy and secure fashion. Think of Jam as a band playing perfectly in sync: replace the instruments with end users, support staff and software developers playing in tune—and better yet, you’ll never have to take requests for “Free Bird.”</p><p>If this is your first time learning about Jam, here's a quick rundown. Users of your site can use a Chrome extension to share the full context of an issue, allowing your support team to analyze the data immediately. If needed, developers can reproduce and debug the issue using the <a href="https://www.telerik.com/fiddler/fiddler-everywhere?ref=daveabrock.com">Fiddler Everywhere debugging proxy</a>. (If you'd like to learn more about Fiddler Jam basics, <a href="https://www.telerik.com/blogs/introducing-fiddler-jam?ref=daveabrock.com#:~:text=Fiddler%20Jam%20is%20a%20troubleshooting%20solution%20for%20support,%28S%29%20network%20logs%20in%20the%20customer%27s%20own%20environment.">check out Rob Lauer's article</a>.)</p><p>Jam already has a great set of features, but the development team—let's call them Jammers—has pushed even more capabilities and improvements since we last talked. We can put it through its paces by taking a look at my Blast Off with Blazor site, <a href="https://www.daveabrock.com/2020/10/26/blast-off-blazor-intro/">which I've written about</a>. Let's see what the Jammers have been up to.</p><h2 id="video-recordings">Video recordings</h2><p>When we last talked, we were able to see screenshots of a lot of user actions so we could see what users were doing when issues occurred. When you start to look at a sequence of actions, though, it might be hard to work through all the steps one by one. My favorite update is definitely a new video recording feature.</p><p>After a user sends your support team a link to their Jam session, you’ll notice that the first item in the log (“Capturing Started”) is a full video recording of their experience. This only records the tab in which the user allowed their session to be captured. At this phase, you can choose to watch the whole video.</p><p>As you watch it, notice how the recording highlights the corresponding log entries as they are happening. You can pause the video where needed and go right where you need to be with full context. You can also click on an event in the log and be sent to the place in the video where it occurred. From there, you can play the recording or go back and forward as needed. Instead of dealing with word-of-mouth context, you’ve got everything you need.</p><p>In my case, I have a 14-second capture full of lots of media, searching and scrolling. Watch the play icon at the left and how it jumps through the log events as time passes. Very cool.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/play-video-2.gif" class="kg-image" alt loading="lazy" width="1920" height="1066"></figure><p>While this is a powerful feature, Corporate Dave is here to inform you that Jam enables video recordings and screenshots by default. Be careful when dealing with sensitive data like passwords, credit card numbers, or anything else you want to keep private. Read <em><a href="https://docs.telerik.com/fiddler-jam/security?ref=daveabrock.com#capture-options">Fiddler Jam Security</a></em><a href="https://docs.telerik.com/fiddler-jam/security?ref=daveabrock.com#capture-options"> for details</a>.</p><h2 id="better-tracking-for-user-events">Better tracking for user events</h2><p>When we last Jam'ed, I briefly discussed how Fiddler Jam could track a few common events, like button clicks. The Jammers have cranked this up a notch and now allow you to track a ton of other events like clicking on <code>div</code> elements, keyboard events, and scroll events. </p><p>I don't know about you, but when I debug front-end issues, it isn't as easy as finding that a file wasn't found or there's a big error in the browser console. It's subtle things that make me clamor for the simplicity of Geocities, <a href="https://javascript.info/bubbling-and-capturing?ref=daveabrock.com">like event bubbling</a> and misapplied styles.</p><p>The Jammers now give us the ability to click the Inspectors tab to understand metadata about the event, like tag type and CSS class. In addition to video recording, you'll see I also have the event highlighted (in this case, typing into a search box) in a convenient screenshot.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-1.png" class="kg-image" alt loading="lazy" width="1629" height="1063" srcset="https://www.daveabrock.com/content/images/size/w600/2021/09/image-1.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/09/image-1.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/09/image-1.png 1600w, https://www.daveabrock.com/content/images/2021/09/image-1.png 1629w" sizes="(min-width: 720px) 720px"></figure><h2 id="capture-storage-information">Capture storage information</h2><p>A new option, <em>Capture storage info</em>, allows you to capture <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage?ref=daveabrock.com">local storage</a> and session storage data. If you aren't familiar, local and session storage are HTML5 storage objects that allow you to store data on the client using convenient key-value pairs. Local storage exists until deleted and has no expiration date, while session storage deletes the data when the user closes a browser.</p><p>While Corporate Dave will tell you to not store sensitive data here—as local/session storage isn't super secure and, also, the data is easily accessible and hackable from standard browser tooling—it can sometimes be a lightweight solution for simple data lookup. It can work well with simple user preferences or activities: if we want to remember that a user prefers Dark Mode or has already seen our introductory modal that tours our website, we can store it in local storage for easy retrieval.</p><p>The Jammers have introduced the ability for you to view storage details from an aptly named Storage Details tab. If I go to a random website—look, the Telerik Blogs website, what a coincidence!—I can determine when a local storage value was set, and what it is.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-3.png" class="kg-image" alt loading="lazy" width="2000" height="1472" srcset="https://www.daveabrock.com/content/images/size/w600/2021/09/image-3.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/09/image-3.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/09/image-3.png 1600w, https://www.daveabrock.com/content/images/2021/09/image-3.png 2139w" sizes="(min-width: 720px) 720px"></figure><h2 id="how-do-the-advanced-options-work-now">How do the Advanced Options work now?</h2><p>With all these great updates, let's take a look at the new <a href="https://docs.telerik.com/fiddler-jam/get-started/capture-options?ref=daveabrock.com">Advanced Options</a> that users can set before capturing a session with Fiddler Jam. Most of these are enabled by default, so you won't have to ask users to explicitly turn them on, but let's review. (Don't worry, there isn't a quiz ... yet.) </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-2.png" class="kg-image" alt loading="lazy" width="400" height="443"></figure><p>Unless stated otherwise, all these options are enabled by default.</p><ul><li><strong>Capture video </strong>- As we discussed, this option captures video recording from the active, inspected Chrome tab. Corporate Dave says: "If the screen shows sensitive data, consider disabling it."</li><li><strong>Capture screenshots</strong> – This option adds a screenshot from the active Chrome tab. Corporate Dave says: "If the screen shows sensitive data, consider disabling it."</li><li><strong>Capture console</strong> – This option records any developer console outputs. Again, consider disabling this if your logs have sensitive information. </li><li><strong>Capture storage info</strong> - This option captures local or session storage from the Chrome tab. </li><li><strong>Mask cookies</strong> – This option masks cookie values so that they aren’t visible in the logs. The cookie names will still be visible. </li><li><strong>Mask all post data</strong> – This option masks data sent along in a POST request, like form information. <em>This option is not enabled by default.</em></li><li><strong>Disable cache</strong> – This option asks the browser to skip network requests cache and download fresh content from the server.  </li></ul><h2 id="updated-sharing-options">Updated sharing options</h2><p>In addition to these new Advanced Options, end users can also view capture details and customize who needs to access the session's details.</p><p>First, users can access session details by clicking <em>Capture Successful! </em>I imagine the exclamation point to show the excitement that a user's issue will be diagnosed so quickly! Yes!</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/capture-successful.png" class="kg-image" alt loading="lazy" width="554" height="807"></figure><p>Users can click this area to see a quick event log. It's a nice sanity check so users can confirm they are sending you the right logs. If they have 92 tabs open—I would never, but some might—this will help provide a sanity check to make sure they are passing the correct session to you, and not cute cat videos. Again, I would never.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-4.png" class="kg-image" alt loading="lazy" width="549" height="707"></figure><p>After optionally confirming users are sending the right tab, users can choose to share the details as a link or with specific people. When sharing as a link, I (and Corporate Dave) would suggest using the Password Protection feature. </p><p>When you share with specific people, enter the recipient email addresses(es) to send it over electronic mail. When you do this, only the people with corresponding email addresses will have access to it.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-5.png" class="kg-image" alt loading="lazy" width="546" height="870"></figure><h2 id="more-coming">More coming!</h2><p>There's more coming to Fiddler Jam soon—consider <a href="https://www.telerik.com/support/whats-new/fiddler-jam/roadmap?ref=daveabrock.com">bookmarking the Fiddler Jam roadmap</a> for details. </p><p>Get started with Fiddler Jam today by going to the Fiddler Jam site and <a href="https://www.telerik.com/fiddler-jam?ref=daveabrock.com">signing up for a free 14-day trial</a>. </p><p>Pretty good work from the Jammers, yes? Good work, team. Take the rest of the day off. You've deserved it.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Saying goodbye to The .NET Stacks ]]></title>
        <description><![CDATA[ In this post, I&#39;m writing a quick note to say I&#39;m ending The .NET Stacks. ]]></description>
        <link>https://www.daveabrock.com/2021/11/04/bye-dotnet-stacks/</link>
        <guid isPermaLink="false">6182c17efb01aa003b337307</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Thu, 04 Nov 2021 07:42:14 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1494364836865-dca29a6d9334?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDN8fGdvb2RieWV8ZW58MHx8fHwxNjM2MDI4MzY2&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>I wanted to write a quick note to let everyone know that I will no longer be producing <em>The .NET Stacks</em>. This does not mean I'll be going away or leaving the wonderful .NET community—it just means I'll be producing content in other ways.</p><p>I wouldn't call the newsletter a smashing success by any means, but was thrilled that something I started while bored during a pandemic grew to a few thousand readers every week on various mediums (whether over e-mail, <em>dev.to</em>, or <em>daveabrock.com</em>). I'm grateful to all of you for reading and being so supportive—and if it helped you, I'm even happier. It's been a lot of fun and I've even "met" quite a few friends along the way, even if we've never physically met.</p><p>I initially set out to produce something more substantive and not a weekly thing where I send out links every week, as I felt there wasn't a lot of that out there. I wanted to write about trends and topics, and interview folks, and provide a little more context. I quickly realized why there wasn't a lot of that out there: it's so much work to do that on a weekly basis, week in, week out. </p><p>With a busy personal life, I'm passionate about community work but with limited time. I did a lot of work to automate things as I could, but <em>The .NET Stacks</em> doesn't leave time for any other community work or projects that I'm passionate about. To me, I could either slim down the newsletter and its quality and make it easier to manage, or focus work in other areas. I've chosen the latter.</p><p>It's hard to believe I've produced 70 weekly issues over 18 months, and have used the newsletter to ramble about .NET to the tune of about 104,000 words. Thanks to you all: thanks for reading every week, and thanks for those of you who have emailed me nice words or to ask if I've lost my marbles—both valid, by the way—and thanks for listening. I hope you'll continue to keep up with me at<em> daveabrock.com</em>. Talk to you soon and keep in touch.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #68: 🍿 What a week ]]></title>
        <description><![CDATA[ In this issue, we talk about an eventful week in the .NET community. ]]></description>
        <link>https://www.daveabrock.com/2021/10/26/dotnet-stacks-68/</link>
        <guid isPermaLink="false">6176d3fc476ac6003bb3a814</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 26 Oct 2021 18:27:37 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/10/THE-.NET-STACKS-3.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy ... Tuesday? It's been quite an interesting week. We have one thing to discuss, and then straight to the links. </p><ul><li>.NET Open Source: Who does Microsoft want to be?</li><li>Last week in the .NET world</li></ul><hr><h2 id="net-open-source-who-does-microsoft-want-to-be">.NET Open Source: Who does Microsoft want to be?</h2><p>To put it lightly, last week was a very eventful week for the .NET community. I'd like to talk about what happened, what we learned, and what it means for .NET open source.</p><p>Before diving in, I want to say that I am voicing my opinions only and my intent is not to "create more drama" or keep harping on about past events. While Microsoft resolved the current issue a few days ago, I often find that I can view events with better clarity after spending a few days stepping back and thinking about it. You might agree with what I have to say, think I'm blowing it out of proportion, or somewhere in between. I expect that.</p><p>What happened? If you've been subscribed here for the last few months, you know that one of the core objectives of .NET 6 is to <a href="https://github.com/dotnet/core/issues/5511?ref=daveabrock.com">improve the "inner development loop" for the .NET platform</a>. The core feature is the "Hot Reload" functionality, which allows developers to see changes applied instantly while running their application. Already viewed as table stakes for modern web application development—front-end developers have enjoyed this capability for many years—it's finally making its way to the .NET platform. As the .NET team is trying to embrace new developers or developers from other platforms, it's a key selling point. If you try to get React or Angular developers to consider something like Blazor, and they learn it isn't available out of the box, you'll likely get a "Seriously?" Once you have it, you can't live without it.</p><p>Anyway, Hot Reload was announced and then rolled out in .NET 6 Preview 3, and I wrote about it in detail <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">all the way back in April</a>. At the time, it was rolled out in the .NET CLI via <code>dotnet watch</code> as a lot of new features are. Eventually, Microsoft said, it would make its way to Visual Studio or whatever tool you enjoy—but since it resides in the core SDK, you could use it across a wide variety of environments and platforms. It worked well and as a whole, the community was thrilled. Right around the time .NET 6 RC 2 was released last week—the last "preview" release that ships with a go-live production license—Microsoft decided to scrap it from <code>dotnet watch</code> and only make it <a href="https://devblogs.microsoft.com/dotnet/update-on-net-hot-reload-progress-and-visual-studio-2022-highlights/?ref=daveabrock.com">available for Visual Studio 2022</a> "so we can focus on providing the best experiences to the most users" so long as you enjoy Visual Studio on Windows. As if it wasn't abundantly clear, .NET engineers leaked to <em>The Verge</em> that this was a <a href="https://www.theverge.com/2021/10/22/22740701/microsoft-dotnet-hot-reload-removal-decision-open-source?ref=daveabrock.com">business decision made at the CVP level</a>.</p><p>After a ton of almost <a href="https://github.com/dotnet/sdk/issues/22247?ref=daveabrock.com">universal backlash</a>, the capability <a href="https://devblogs.microsoft.com/dotnet/net-hot-reload-support-via-cli/?ref=daveabrock.com">was restored</a> to <code>dotnet watch</code>, in a blog post whose only strength was providing political cover and delivered on none of what we all wanted: being honest, authentic, or transparent with the community.</p><p>I don't think anyone is confusing a trillion-dollar corporation for being a charitable organization. And it is true that a majority of .NET developers are on Visual Studio. If Microsoft decided to make this a Visual Studio feature from the beginning, the pushback would be minimal.</p><p>The deserved furor comes from Microsoft ripping out a core feature right before completing a release and done with a PR that was closed to community feedback. This all feels like we got transported to Ballmer-esque Microsoft, and not the "new Microsoft" that appears to be less concerned with sticking you to specific tooling but doing all it can to meet you where you are, so long as you deploy your workloads to Azure.</p><p>With the popularity of Visual Studio Code and the emergence of wonderful competitive tools like JetBrains Rider, Microsoft is at odds with being open in the name of that fat Azure cash or being protective of pricey enterprise licensing with Visual Studio. This week highlighted their conflict of interest and desire to have their cake and eat it, too.</p><p>We've been slowly reaching a breaking point. Over the last few years, Microsoft <a href="https://github.com/dotnet/core/issues/505?ref=daveabrock.com">restricted debugger licensing</a>, the <a href="https://blog.lextudio.com/the-end-of-monodevelop-80b383dab34b?ref=daveabrock.com">abandonment of MonoDevelop</a>, and now we have the hot reload controversy. Include the .NET Foundation issues, and Microsoft's "open-source friendly" reputation has taken its hits. The common logic is that while Visual Studio is a moneymaker, for sure, it's a rounding error compared to Azure, so it's good business sense for Microsoft to shed its protectionism in favor of inclusiveness and community goodwill.</p><p>Of course, none of this criticism should take away from the amazing work the .NET team has done for both their platform and open source. As a matter of fact, that team is likely the most upset here as a decision out of control has hurt their reputation with the community. But where does .NET fit? For me, it begs the question about how Microsoft views .NET: is it an open, innovative platform that drives Azure investment, or a piggy bank that Microsoft executives can shake until every last penny comes out?</p><p>To Microsoft's credit, they should be commended for writing their wrongs so quickly. They listened and reacted, and pushed out an apology in just a few days—an amazing feat at a trillion-dollar company with many layers of top-down management. All in all, I think last week was a wonderful testament to the true value of community, where a group of devoted people can help drive change (or undo unfortunate decisions).</p><p>However, <a href="https://devblogs.microsoft.com/dotnet/net-hot-reload-support-via-cli/?ref=daveabrock.com">the apology post</a> is littered with inconsistencies and seems to be protecting senior management's decisions and not their reputation with the community.</p><p>The post explains that: "In our effort to scope, we inadvertently ended up deleting the source code instead of just not invoking that code path." In my opinion, this wasn't an engineer running the wrong command, but trying to make a last-minute change at the demands of their management and closing the PR for comments. While reading the post, I couldn't help but feel how it contradicted this new open Microsoft—build what you want, on any platform you want, so long as you use Azure—and reeked of the political cover and protectionism that defined its past.</p><p>Where do we go from here? Is this a team hitting some bumps with a recent reorg, or a sign of things to come? Have the higher-ups at Microsoft learned their lessons, or is this the beginning of protecting the most coveted SDK features to their exclusive tooling? And most importantly, how will Microsoft balance conflicts of interest with all their tooling choices? As Visual Studio Code is an amazing editor, as <a href="https://dusted.codes/can-we-trust-microsoft-with-open-source?ref=daveabrock.com">Dustin Gorski</a> and others have wondered aloud, isn't it strange that Microsoft's own .NET platform is one of the worst supported platforms on Code?</p><p>If Microsoft wants to be honest with its community, it needs to answer: What do you want .NET to be? To keep it an open, open-source friendly platform, or to make it a piggy bank? It appears to be that Microsoft wants it both ways and risks harming its reputation with the community while promising openness.</p><p>We know Microsoft will never have a perfect relationship with its developer community. At the end of the day, their responsibilities are to their shareholders. With that said, I have all the faith in the world in the .NET team. I admire them and all the work they have done on the .NET platform. I hope the team aligns with their management and can eventually be transparent with the community about what they truly want .NET to be—no BS, no corporate-speak.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3></h3><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Emily Stoll <a href="https://devblogs.microsoft.com/visualstudio/weve-upgraded-the-ui-in-visual-studio-2022?ref=daveabrock.com" rel="nofollow">writes about Visual Studio 2022 UI updates</a>.</li><li>Dmitry Lyalin <a href="https://devblogs.microsoft.com/dotnet/update-on-net-hot-reload-progress-and-visual-studio-2022-highlights?ref=daveabrock.com" rel="nofollow">provides an update on .NET Hot Reload</a>.</li><li>Microsoft introduces <a href="https://code.visualstudio.com/blogs/2021/10/20/vscode-dev?ref=daveabrock.com" rel="nofollow">vscode.dev</a>.</li><li>Paul Thurrott <a href="https://www.thurrott.com/dev/258377/microsoft-officially-deprecates-uwp?ref=daveabrock.com" rel="nofollow">writes about Microsoft deprecating UWP</a>.</li><li>Kathleen Dollard <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-fsharp-6?ref=daveabrock.com" rel="nofollow">writes about what's new in F# 6</a>.</li><li>Microsoft releases <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release?ref=daveabrock.com" rel="nofollow">Windows Terminal Preview 1.12</a>.</li><li>Rachel Appel <a href="https://blog.jetbrains.com/dotnet/2021/10/20/debugging-experience-debug-uwp-apps-and-debug-windows-docker-containers-in-rider-2021-3/?ref=daveabrock.com" rel="nofollow">writes about various updates in Rider 2021.3</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Help decide <a href="https://dotnetfoundation.org/blog/2021/10/18/net-foundation-face-to-face-questions?ref=daveabrock.com" rel="nofollow">what questions to answer at the .NET Foundation's next meeting</a>.</li><li>The Uno Blog <a href="https://platform.uno/blog/recent-uwp-and-net-5-net-6-news-and-uno-platform-plans/?ref=daveabrock.com" rel="nofollow">writes about recent UWP &amp; .NET 5, .NET 6 news and Uno Platform plans</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/the-ghost-of-silverlight-or-lessons-learned-from-dying-frameworks-cb745b16a61f?ref=daveabrock.com" rel="nofollow">writes about lessons learned from dying frameworks</a>.</li><li>Sergey Tihon <a href="https://sergeytihon.com/2021/10/18/f-advent-calendar-2021/?ref=daveabrock.com" rel="nofollow">announces the 2021 F# advent calendar</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Richard MacManus <a href="https://thenewstack.io/growth-of-progressive-web-apps/?ref=daveabrock.com" rel="nofollow">writes about the growth of PWAs</a>.</li><li>The Microsoft Edge Blog <a href="https://blogs.windows.com/msedgedev/2021/10/21/improved-authoring-debugging-devtools-visual-studio-code?ref=daveabrock.com" rel="nofollow">writes about the improved authoring and debugging experiences in Microsoft Edge DevTools and Visual Studio Code</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/csharptips/ping-endpoint?ref=daveabrock.com" rel="nofollow">writes about pinging endpoints</a>.</li><li>Imar Spaanjars <a href="https://imar.spaanjaars.com/626/improving-your-aspnet-core-sites-file-handling-capabilities-part-1-introduction?ref=daveabrock.com" rel="nofollow">writes about improving your ASP.NET Core site's file handling capabilities</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/10/15/aspnet-update.aspx?ref=daveabrock.com" rel="nofollow">writes about native dependencies with Blazor WebAssembly</a>.</li><li>Chris Coyier <a href="https://css-tricks.com/supports-selector/?ref=daveabrock.com" rel="nofollow">writes about the supports() CSS selector</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Matthew Jones <a href="https://exceptionnotfound.net/bite-size-dotnet-6-linq-ordefault-overloads/?ref=daveabrock.com" rel="nofollow">uses LINQ OrDefault() overloads in .NET 6</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-6-supporting-integration-tests-with-webapplicationfactory-in-dotnet-6/?ref=daveabrock.com" rel="nofollow">supports integration tests with WebApplicationFactory in .NET 6</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Dave Brock <a href="https://www.daveabrock.com/2021/10/21/csharp-10-global-usings/" rel="nofollow">writes about using global declarations in C# 10</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/bulk-import-records-into-sqlite-csharp?ref=daveabrock.com" rel="nofollow">uses C# to bulk insert records into SQLLite</a>.</li><li>Jorge Levy <a href="https://www.c-sharpcorner.com/article/azure-functions-with-net-5-execution-on-isolated-process/?ref=daveabrock.com" rel="nofollow">writes about using Azure Functions with .NET 5</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/10/21/c-10-extended-property-patterns/?ref=daveabrock.com" rel="nofollow">talks about extended property patterns in C# 10</a>.</li><li>Muhammed Saleem <a href="https://code-maze.com/csharp-async-enumerable-yield/?ref=daveabrock.com" rel="nofollow">uses IAsyncEnumerable with yield in C#</a>.</li><li>David McCarter <a href="https://dotnettips.wordpress.com/2021/10/21/collection-performance-converting-a-list-to-different-types/?ref=daveabrock.com" rel="nofollow">writes about collection type performance in C#</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Thomas Scott <a href="https://dzone.com/articles/5-jetbrain-plugins-upgrade-git-support?ref=daveabrock.com" rel="nofollow">talks about JetBrains Git plugins</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/exploring-auth0-aspnet-core-authentication-sdk/?ref=daveabrock.com" rel="nofollow">explores the Auth0 ASP.NET Core Authentication SDK</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Zaher Talab <a href="https://www.developer.com/web-services/api-testing-tools-tips/?ref=daveabrock.com" rel="nofollow">provides API testing tips</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/leaking-value-objects-from-your-domain/?ref=daveabrock.com" rel="nofollow">writes about leaking value objects from your domain</a>.</li><li>Sam Milbrath <a href="https://blog.trello.com/4-ways-to-manage-your-energy-and-have-a-balanced-productive-workday?ref=daveabrock.com" rel="nofollow">writes about managing your energy</a>.</li><li>The Overflow Blog <a href="https://stackoverflow.blog/2021/10/18/code-quality-a-concern-for-businesses-bottom-lines-and-empathetic-programmers/?ref=daveabrock.com" rel="nofollow">writes about code quality</a>.</li><li>The Stackify Blog <a href="https://stackify.com/net-developer-skills/?ref=daveabrock.com" rel="nofollow">discusses top .NET developer skills</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/195041-C/finding-a-bug-with-code-that-isnt-there?Key=ce6fc440-4aef-4063-b1ca-f6337258b17f&ref=daveabrock.com" rel="nofollow">tracks down a sticky bug</a>.</li><li>Joana Carvalho <a href="https://dzone.com/refcardz/full-stack-observability-essentials?ref=daveabrock.com" rel="nofollow">writes about full-stack observability essentials</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/unit-testing-azure-functions-in-isolated-environment?ref=daveabrock.com" rel="nofollow">unit tests Azure Functions</a>.</li><li>Dennis Doomen <a href="https://www.continuousimprover.com/2021/10/laws-test-driven-development.html?ref=daveabrock.com" rel="nofollow">writes about his 17 laws of TDD</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The .NET Podcast <a href="https://dotnetcore.show/episode-85-clean-code-in-c-sharp-with-jason-alls/?ref=daveabrock.com" rel="nofollow">talks about clean code in C#</a>.</li><li>Merge Conflict <a href="https://www.mergeconflict.fm/276?ref=daveabrock.com" rel="nofollow">writes about .NET 6 and C# 10</a>.</li><li>Adventures in .NET <a href="https://adventuresindotnet.com/how-fluent-are-your-assertions-net-091?ref=daveabrock.com" rel="nofollow">talks to Dennis Doomen about Fluent Assertions</a>.</li><li>The Overflow <a href="https://stackoverflow.blog/2021/10/22/podcast-386-quality-code-is-the-easiest-to-delete/?ref=daveabrock.com" rel="nofollow">talks about code quality</a>.</li><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-216-visual-studio-2022-with-mads-kristensen/?ref=daveabrock.com" rel="nofollow">talks to Mads Kristensen about Visual Studio 2022</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=QUHa7ojibjY&ref=daveabrock.com" rel="nofollow">talk about improved .NET 6 LINQ methods</a>.</li><li>Cecil Phillip <a href="https://www.youtube.com/watch?v=AAQSShtl9S0&ref=daveabrock.com" rel="nofollow">walks through Dapr</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #67: 🆕 .NET 6 RC2 arrives ]]></title>
        <description><![CDATA[ In this issue, we talk about the release of .NET 6 RC2 and a new LINQ API. ]]></description>
        <link>https://www.daveabrock.com/2021/10/24/dotnet-stacks-67/</link>
        <guid isPermaLink="false">616ad8af35ee50003b3897c5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 24 Oct 2021 11:39:29 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/10/THE-.NET-STACKS-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another week, full of <a href="https://www.theverge.com/2021/10/18/22732912/apple-macbook-pro-notch-display?ref=daveabrock.com">top-notch product announcements</a> and the proclamation of "View Source" <a href="https://twitter.com/GovParsonMO/status/1448697768311132160?ref=daveabrock.com">as a crime</a>.  I too am a hacker, apparently.</p><p>Anyway, here's what we have going on this week:</p><ul><li>Web updates with .NET 6 RC 2</li><li>New .NET 6 LINQ API: Chunk</li><li>Last week in the .NET world</li></ul><hr><h2 id="web-updates-with-net-6-rc-2">Web updates with .NET 6 RC 2</h2><p>Right on time, last week Microsoft <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com">rolled out the .NET 6 RC 2 release</a>. It's the second of two "go live" RCs that are actually supported in production. Richard Lander's announcement post gets you up to speed on <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#c-10">what is new with C# 10</a>, including <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#record-structs">record structs</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#global-usings">global usings</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#file-scoped-namespace-declaration">file-scoped namespaces</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#const-and-interpolated-strings">interpolated strings</a>, and <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#extended-property-patterns">extended property patterns</a>. </p><p>Despite being oh-so-close to the official release next month, the ASP.NET Core team was busy shipping updates for this release and I'd like to <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2/?ref=daveabrock.com">pay attention to those</a>. We saw updates in two big areas: <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2/?ref=daveabrock.com">native dependencies</a> and Minimal APIs—the latter of which I've admittedly beaten to death, but also plays a pivotal future in how you build new APIs in the .NET ecosystem (if you want to get over MVC, of course).</p><p>With Blazor WebAssembly, in .NET 6 you can now use native dependencies that are built to run on WebAssembly. Using new .NET WebAssembly build tools, you can statically link native dependencies. You can use any native code with this, like C/C++ code, archives, or even standalone .wasm modules. If you have some C code, for example, the build tools can compile and link it to a <code>dotnet.wasm</code> file. To extend it some more, you can use libraries with native dependencies as well.</p><p>As for Minimal APIs, you can now leverage parameter binding improvements. With RC2, you can use <code>TryParse</code> and <code>BindAsync</code> for inherited methods. For example, <code>BindAsync</code> allows you to bind a complex type using inheritance. Check out Daniel Roth's <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2/?ref=daveabrock.com#parameter-binding">blog post for details</a>. The RC2 release also makes some <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2/?ref=daveabrock.com#openapi">OpenAPI enhancements</a> and includes some analyzers to help you find issues with <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2/?ref=daveabrock.com#source-code-analysis">middleware issues or route handling</a>. </p><p>It's hard to believe the next .NET 6 announcement will be the full release itself. As part of that <a href="https://www.dotnetconf.net/?ref=daveabrock.com">.NET Conf will celebrate the launch</a>, and Visual Studio 2022 will launch on November 8. In the year 2021. (I know.)</p><hr><h2 id="new-net-6-linq-api-chunk">New .NET 6 LINQ API: Chunk</h2><p>If you haven't heard, .NET 6 will roll out some nice LINQ API improvements. Matt Eland recently <a href="https://raygun.com/blog/linq-net-6-improvements/?ref=daveabrock.com">wrote a nice piece about them</a>. As a whole, it's nice to see .NET 6 roll out quite a few API improvements that were previously done with some light hacking. We all do some light hacking, of course, but for millions of .NET developers there are a lot of common use cases—and it's nice to see those being addressed.</p><p>My favorite recent LINQ API improvement is the Chunk API. If you work with large collections of objects, you can now chunk them in case you want to work through pagination or other "chunking" use cases. For paging, you previously had to set a page size, loop through the collection, add to some paging collection, and update some counts. </p><p>Instead, as Matt notes, you could try something like this:</p><pre><code class="language-csharp">IEnumerable&lt;Movie[]&gt; chunks = movies.Chunk(PAGE_SIZE);</code></pre><p>This should really help folks page through big API datasets. When you don't control the data coming back, you had to set this up yourself. Very nice.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3></h3><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2?ref=daveabrock.com" rel="nofollow">announces .NET 6 Preview 2</a>, and Daniel Roth discusses <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-2?ref=daveabrock.com" rel="nofollow">ASP.NET Core updates</a>. Also, David Ortinau <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-9?ref=daveabrock.com" rel="nofollow">introduces .NET MAUI Preview 9</a>.</li><li>Visual Studio 2022 for Mac Preview 2 <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-for-mac-preview-2-is-now-available?ref=daveabrock.com" rel="nofollow">is now available</a>.</li><li>Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/prime-your-flux-capacitor-sql-server-temporal-tables-in-ef-core-6-0?ref=daveabrock.com" rel="nofollow">writes about SQL Server temporal tables in EF Core 6</a>.</li><li>Auth0 is now <a href="https://auth0.com/blog/auth0-on-microsoft-azure-as-a-private-cloud-deployment-option/?ref=daveabrock.com" rel="nofollow">available on Azure</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Brendan Burns <a href="https://cloudblogs.microsoft.com/opensource/2021/10/13/kubecon-north-america-2021-kubernetes-on-azure-and-open-source-updates?ref=daveabrock.com" rel="nofollow">provides updates on KubeCon</a>.</li><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/10/11/marten-v4-hard-deletes-soft-deletes-un-deletes-all-the-deletes-you-meet/?ref=daveabrock.com" rel="nofollow">writes all about deletes in Marten v4</a>.</li><li>Aaron Stannard <a href="https://aaronstannard.com/future-of-dotnet-foundation/?ref=daveabrock.com" rel="nofollow">writes about the Future of the .NET Foundation and .NET OSS</a>. In related news, The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/10/14/come-talk-to-us-a-net-foundation-face-to-face?ref=daveabrock.com" rel="nofollow">is holding a Tell Me Anything meeting</a>.</li><li>Microsoft has a VS 2022 launch event <a href="https://devblogs.microsoft.com/visualstudio/join-us-november-8th-for-the-launch-of-visual-studio-2022?ref=daveabrock.com" rel="nofollow">on November 8</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Vedran Cindric <a href="https://dzone.com/articles/the-rest-of-the-10-commandments?ref=daveabrock.com" rel="nofollow">provides some REST guidance</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/get-your-head-together-with-blazors-new-headcontent-and-pagetitle?ref=daveabrock.com" rel="nofollow">works with Blazor’s new HeadContent and PageTitle</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/blazors-aot-compilation-isn-t-the-silver-bullet-you-re-expecting-2a454e524bc7?ref=daveabrock.com" rel="nofollow">throws some cold water on Blazor AOT compilation</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/dotnet-could-not-execute-because-the-application-was-not-found-or-a-compatible-net-sdk-is-not-installed?ref=daveabrock.com" rel="nofollow">debugs a .NET SDK issue</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/bite-size-dotnet-6-chunk-in-linq/?ref=daveabrock.com" rel="nofollow">writes about the new Chunk() method in .NET 6</a>.</li><li>Code Maze <a href="https://code-maze.com/cqrs-mediatr-fluentvalidation/?ref=daveabrock.com" rel="nofollow">works through a CQRS validation pipeline with MediatR and FluentValidation</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-5-supporting-ef-core-tools-with-webapplicationbuilder/?ref=daveabrock.com" rel="nofollow">supports EF Core migrations with WebApplicationBuilder</a>.</li><li>Muhammad Rehan Saeed <a href="https://rehansaeed.com/the-problem-with-csharp-10-implicit-usings/?ref=daveabrock.com" rel="nofollow">writes about his issues with C# 10 implicit usings</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Lee Briggs <a href="https://www.pulumi.com/blog/azure-container-solutions/?ref=daveabrock.com" rel="nofollow">compares Azure container solutions</a>.</li><li>Norm Johanson <a href="https://aws.amazon.com/blogs/developer/dotnet-deployment-projects/?ref=daveabrock.com" rel="nofollow">writes about the new AWS .NET Deployment Experience</a>, and François Bouteruche <a href="https://medium.com/i-love-my-local-farmer-engineering-blog/migrating-our-trusty-ol-net-framework-applications-to-aws-i-couldn-t-believe-it-2b111fcd8146?ref=daveabrock.com" rel="nofollow">migrates .NET Framework apps to AWS</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Asynchronous-communication-with-Azure-Service-Bus/?ref=daveabrock.com" rel="nofollow">writes about async communication with the Azure Service Bus</a>.</li><li>Pavel Krymets <a href="https://devblogs.microsoft.com/azure-sdk/introducing-experimental-opentelemetry-support-in-the-azure-sdk-for-net?ref=daveabrock.com" rel="nofollow">introduces experimental OpenTelemetry support in the Azure SDK for .NET</a>.</li><li>Stephanie Lee <a href="https://medium.com/asos-techblog/azure-functions-in-net-5-6faae95c1b72?ref=daveabrock.com" rel="nofollow">writes about using Azure Functions with .NET 5</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/cursor-paging-with-entity-framework-core-and-aspnet-core?ref=daveabrock.com" rel="nofollow">works on cursor paging with Entity Framework Core and ASP.NET Core</a>.</li><li>The Pro Code Guide <a href="https://procodeguide.com/programming/polly-in-aspnet-core/?ref=daveabrock.com" rel="nofollow">uses Polly with ASP.NET Core</a>.</li><li>James Croft <a href="https://www.jamescroft.co.uk/running-selenium-ui-tests-in-an-azure-devops-pipeline/?ref=daveabrock.com" rel="nofollow">runs Selenium UI Tests with Azure DevOps</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/enable-net-cli-tab-completion?ref=daveabrock.com" rel="nofollow">enables .NET CLI tab completion</a>.</li><li>Thomas Ardal writes about <a href="https://blog.elmah.io/updating-nuget-packages-from-command-line-deep-dive/?ref=daveabrock.com" rel="nofollow">updating NuGet packages from the command line</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/serilog-log-on-console?ref=daveabrock.com" rel="nofollow">adds logs with .NET Core and Serilog</a>.</li><li>Grace Taylor <a href="https://devblogs.microsoft.com/visualstudio/vs-code-themes-in-vs?ref=daveabrock.com" rel="nofollow">writes about using VS Code themes with Visual Studio 2022</a>.</li><li>Matthias Koch <a href="https://blog.jetbrains.com/dotnet/2021/10/11/copy-code-reference-in-resharper-and-rider-2021-3-eap/?ref=daveabrock.com" rel="nofollow">writes about the reworked Copy Code Reference feature in ReSharper and Rider 2021.3 EAP</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Derek Comartin <a href="https://codeopinion.com/data-consistency-between-microservices/?ref=daveabrock.com" rel="nofollow">explores data consistency between microservices</a>.</li><li>Camille Fournier <a href="https://www.elidedbranches.com/2021/10/how-new-managers-fail-individual.html?ref=daveabrock.com" rel="nofollow">writes about how new managers fail individual contributors</a>.</li><li>Dennis Doomen <a href="https://www.continuousimprover.com/2021/10/symptoms-testability.html?ref=daveabrock.com" rel="nofollow">describes 15 flags that tell you that your testability practices need maturing</a>.</li><li>The Overflow <a href="https://stackoverflow.blog/2021/10/13/why-solve-a-problem-twice-design-patterns-let-you-apply-existing-solutions-to-your-code/?ref=daveabrock.com" rel="nofollow">explores design patterns</a>.</li><li>Jennifer Riggins <a href="https://thenewstack.io/observability-is-the-new-kubernetes/?ref=daveabrock.com" rel="nofollow">writes about the emergence of observability</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and videos</h3><ul><li>Adventures in .NET <a href="https://adventuresindotnet.com/vs-2022-64-bit-net-090?ref=daveabrock.com" rel="nofollow">talk about VS 2022</a>.</li><li>The Coding Blocks asks: <a href="https://www.codingblocks.net/podcast/should-you-speak-at-a-conference/?ref=daveabrock.com" rel="nofollow">should you speak at a conference?</a></li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1761&ref=daveabrock.com" rel="nofollow">talks to Mads Torgersen about C# 10</a>.</li><li>AzureFunBytes talks to Burke Holland <a href="https://devblogs.microsoft.com/devops/azurefunbytes-episode-59-remote-possibilities-with-burkeholland?ref=daveabrock.com" rel="nofollow">about remote development</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=lfVEv54BfLE&ref=daveabrock.com" rel="nofollow">build GitHub Actions in C#</a>.</li><li>Scott Hanselman <a href="https://www.youtube.com/watch?v=VT2L1SXFq9U&ref=daveabrock.com" rel="nofollow">makes the ultimate terminal prompt on Windows 11</a>.</li><li>The .NET MAUI Podcast <a href="https://www.dotnetmauipodcast.com/100?ref=daveabrock.com" rel="nofollow">talks all about .NET 6 RC 2</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Exploring C# 10: Global Using Declarations ]]></title>
        <description><![CDATA[ Let&#39;s explore global using directives in C# 10, a nice way to make your namespaces available throughout your project. ]]></description>
        <link>https://www.daveabrock.com/2021/10/21/csharp-10-global-usings/</link>
        <guid isPermaLink="false">616d621235ee50003b3897f5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 20 Oct 2021 22:18:57 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1627389955611-70c92a5d2e2b?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIyfHxnbG9iYWx8ZW58MHx8fHwxNjM0Nzc5NTU5&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome back to my series on new C# 10 features. I kicked off this series by writing about <a href="https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/">file-scoped namespaces</a>, a simple but powerful way to remove unnecessary verbosity from your C# code. This time, we're talking about a new feature that achieves similar goals: global using declarations.</p><p>To see how this works, let's revisit my model from the last post, a <code>Superhero</code>:</p><pre><code class="language-csharp">namespace SuperheroApp.Models;

public class Superhero
{
   public string? FirstName { get; set; }
   public string? LastName { get; set; }
   public string? StreetAddress { get; set; }
   public string? City { get; set; }
   public int? MaxSpeed { get; set; }
}</code></pre><p>Let's say I wanted to do some basic work with this model in a standard C# 10 console application. It would look something like this.</p><pre><code class="language-csharp">using SuperheroApp.Models;

var heroList = new List&lt;Superhero&gt;()
{
    new Superhero
    {
        FirstName = "Tony",
        LastName = "Stark",
        StreetAddress = "10880 Malibu Point",
        City = "Malibu",
        MaxSpeed = 500
    },
    new Superhero
    {
        FirstName = "Natasha",
        LastName = "Romanova",
        MaxSpeed = 200
     }
};

foreach (var hero in heroList)
    Console.WriteLine($"Look, it's {hero.FirstName} {hero.LastName}!");

Console.WriteLine($"The first superhero in the list is {heroList.First().FirstName}.");</code></pre><p>You'll notice that <a href="https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements?ref=daveabrock.com">thanks to top-level statements</a>, the file is already looking pretty slim. If I create a new file, like <code>GlobalUsings.cs</code>, I could store any usings that I want to be shared across my project's C# files. While you can declare global usings anywhere, it's probably a good idea to isolate it somewhere. (This is scoped for the project and not the solution, so if you want this across multiple files you'd want to specify global usings in every project.)</p><pre><code class="language-csharp">global using ConsoleApp6.Models;</code></pre><p>When I go back to my <code>Program.cs</code> file, Visual Studio reminds me that <code>Superhero.Models</code> is referenced elsewhere (in my <code>GlobalUsings.cs</code>), so it can be safely removed.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/image-1.png" class="kg-image" alt loading="lazy" width="653" height="185" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/image-1.png 600w, https://www.daveabrock.com/content/images/2021/10/image-1.png 653w"></figure><p>I can also use the <code>global static</code> keyword when I use common static methods, like the <code>Math</code> class or writing to <code>Console</code>.  While static usings aren't new—they've been around since C# 6—I can use it freely with global usings. Let's update my <code>GlobalUsings.cs</code> file to the following:</p><pre><code class="language-csharp">global using SuperheroApp.Models;
global using static System.Console;</code></pre><p>Back in my <code>Program.cs</code>, Visual Studio tells me I don't need to use <code>Console</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/image-2.png" class="kg-image" alt loading="lazy" width="989" height="276" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/image-2.png 600w, https://www.daveabrock.com/content/images/2021/10/image-2.png 989w" sizes="(min-width: 720px) 720px"></figure><p>Aside from supporting standard namespaces (and system ones) and static namespaces, you can also use aliases. Let's say I wanted to globally use <code>System.DateTime</code> and alias it as <code>DT</code>. Here's how my <code>GlobalUsings.cs</code> file looks now:</p><pre><code class="language-csharp">global using SuperheroApp.Models;
global using static System.Console;
global using DT = System.DateTime;</code></pre><p>Going back to my main <code>Program.cs</code>, here's how everything looks now:</p><pre><code class="language-csharp">var heroList = new List&lt;Superhero&gt;()
{
    new Superhero
    {
        FirstName = "Tony",
        LastName = "Stark",
        StreetAddress = "10880 Malibu Point",
        City = "Malibu",
        MaxSpeed = 500
    },
    new Superhero
    {
        FirstName = "Natasha",
        LastName = "Romanova",
        MaxSpeed = 200
     }
};

foreach (var hero in heroList)
    WriteLine($"Look, it's {hero.FirstName} {hero.LastName}!");

WriteLine($"The first superhero in the list is {heroList.First().FirstName}.");
WriteLine($"Last ran on {DT.Now}");
</code></pre><h2 id="are-some-common-namespaces-globally-available-by-default">Are some common namespaces globally available by default?</h2><p>When I created a collection and read from it, I'm using calls from a few standard Microsoft namespaces: <code>System.Collections.Generic</code> and <code>System.Linq</code>. You may have noticed something: why didn't I need to explicitly include these namespaces in a global usings file? The answer lies in the <code>obj/Debug/net6.0</code> folder. After you build your project, you'll notice a <code>GlobalUsings.g.cs</code> file, which contains <em>implicit usings</em>. Enabled by default in .NET 6, you don't need to explicitly include them.</p><pre><code class="language-csharp">// &lt;auto-generated/&gt;
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;</code></pre><p>The funky <code>global::</code> syntax ensures that you don't see collisions if you have your own namespaces. For example, if I had a few drinks one night and decided to write my own (very buggy) I/O library and call it <code>DaveIsCool.System.IO</code>, this ensures I'm using the Microsoft namespace. </p><p>These usings are driven by an <code>&lt;ImplicitUsings&gt;</code> flag in my project file.</p><pre><code class="language-xml">&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt;
    &lt;OutputType&gt;Exe&lt;/OutputType&gt;
    &lt;TargetFramework&gt;net6.0&lt;/TargetFramework&gt;
    &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt;
    &lt;Nullable&gt;enable&lt;/Nullable&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;</code></pre><p>If you remove the <code>&lt;ImplicitUsings&gt;</code> line, for example, you would see build errors:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/image-3.png" class="kg-image" alt loading="lazy" width="1493" height="188" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/image-3.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/10/image-3.png 1000w, https://www.daveabrock.com/content/images/2021/10/image-3.png 1493w" sizes="(min-width: 720px) 720px"></figure><p>A word of caution: in .NET 6 implicit usings are enabled by default, so if implicit usings aren't for you, this is where you would disable it. For details, take a look at the following document from the .NET team.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/dotnet/core/compatibility/sdk/6.0/implicit-namespaces?ref=daveabrock.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Breaking change: Implicit &#x60;global using&#x60; directives in C# projects - .NET</div><div class="kg-bookmark-description">Learn about the breaking change in .NET 6 where the .NET SDK implicitly includes some namespaces globally in C# projects.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">gewarren</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/dotnet/media/dotnet-logo.png" alt=""></div></a></figure><h2 id="can-i-incorporate-global-usings-with-project-configuration">Can I incorporate global usings with project configuration?</h2><p>To me, it does seem a little strange to be using C# source files to configure project details. If you don't want to use a C# file to specify your global using declarations, you can delete your file and <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-2/?ref=daveabrock.com#global-usings">use MSBuild syntax instead</a>.</p><p>Once you open your project file, you can encapsulate your global usings in an <code>&lt;ItemGroup&gt;</code>, like so:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;Using Include="SuperheroApp.Models"/&gt;
    &lt;Using Include="System.Console" Static="True" /&gt;
    &lt;Using Include="System.DateTime" Alias="DT" /&gt;
&lt;/ItemGroup&gt;</code></pre><h2 id="do-i-have-to-use-these">Do I have to use these?</h2><p>Much like other .NET 6 improvements, you can use it as much or as little as you want. You can use nothing but global and implicit <code>using</code> statements, mix them with regular namespace declarations, or do things as we've always done before. It's all up to you.</p><p>Between C# 9 top-level statements, implicit and global usings, and file-scoped namespaces, the C# team is removing a lot of clutter from your C# files. For example, here's how our <code>Program.cs</code> file would look in C# 8 or older.</p><pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using SuperheroApp.Models;

namespace SuperheroApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var heroList = new List&lt;Superhero&gt;()
            {
                new Superhero
                {
                    FirstName = "Tony",
                    LastName = "Stark",
                    StreetAddress = "10880 Malibu Point",
                    City = "Malibu",
                    MaxSpeed = 500
                },
                new Superhero
                {
                    FirstName = "Natasha",
                    LastName = "Romanova",
                    MaxSpeed = 200
                 }
            };

            foreach (var hero in heroList)
                Console.WriteLine($"Look, it's {hero.FirstName} {hero.LastName}!");

            Console.WriteLine($"The first superhero in the list is {heroList.First().FirstName}.");
            Console.WriteLine($"Last ran on {DT.Now}");
        }
    }
}
</code></pre><p>With top-level statements and global and implicit usings, we now have this.</p><pre><code class="language-csharp">var heroList = new List&lt;Superhero&gt;()
{
    new Superhero
    {
        FirstName = "Tony",
        LastName = "Stark",
        StreetAddress = "10880 Malibu Point",
        City = "Malibu",
        MaxSpeed = 500
    },
    new Superhero
    {
        FirstName = "Natasha",
        LastName = "Romanova",
        MaxSpeed = 200
     }
};

foreach (var hero in heroList)
    WriteLine($"Look, it's {hero.FirstName} {hero.LastName}!");

WriteLine($"The first superhero in the list is {heroList.First().FirstName}.");
WriteLine($"Last ran on {DT.Now}");</code></pre><p>What do you think? Let me know in the comments. Stay tuned for my next topic on CRUD endpoints with the new .NET 6 Minimal APIs.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #66: 🧀 Who moved my cheese? ]]></title>
        <description><![CDATA[ This week, we talk about the impact of the brand new .NET 6 templates, and what that means for you. ]]></description>
        <link>https://www.daveabrock.com/2021/10/18/dotnet-stacks-66/</link>
        <guid isPermaLink="false">61638c98bec39c004adc7061</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 17 Oct 2021 19:38:34 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/10/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p>I know I'm a day or so late. Sorry, I was reading about Web 3.0 and still don't know what it is. Do you? After <a href="https://thenewstack.io/web3-architecture-and-how-it-compares-to-traditional-web-apps/?ref=daveabrock.com">reading this</a>, it made me want to cry, laugh, and then cry again. As if Dapr and Dapper isn't enough, now we have "dapps." </p><p>Anyway, here's what we have going on this week (or last week):</p><ul><li>Who moved my cheese: New templates for .NET 6 might surprise you</li><li>Community spotlight: Marten v4 is now live</li><li>Last week in the .NET world</li></ul><hr><h2 id="who-moved-my-cheese-new-templates-for-net-6-might-surprise-you">Who moved my cheese: New templates for .NET 6 might surprise you</h2><p>As the release of .NET 6 is rapidly approaching—with .NET 6 RC2 coming out <em>very </em>soon with the official release next month—you might be taken aback by C# template changes. The .NET team is leveraging top-level statements and implicit using directives for some new .NET 6 templates. For example, top-level statements are helping to drive new capabilities like <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#introducing-minimal-apis">Minimal APIs</a>. Microsoft has put together a new document, <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/top-level-templates?ref=daveabrock.com"><em>New C# templates generate top-level statements</em></a>, and you should check it out.</p><p>With .NET 6, if you create a new console app using <code>dotnet new console</code> (or from Visual Studio tooling), you might expect to see this:</p><pre><code class="language-csharp">using System;

namespace MyVerboseApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}</code></pre><p>Think again. You'll see this instead:</p><pre><code class="language-csharp">// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");</code></pre><p>Much like with top-level statements, you probably have one of two opinions: it eliminates boilerplate and makes it simpler and more beginner-friendly; or it provides too many abstractions and "I didn't ask for this." I do like top-level statements and agree it eliminates a lot of boilerplate. When it comes to using <code>args</code>, though, I like to see where they are being passed in and not just a magic variable. </p><p>As of now, to stay consistent with Microsoft pushing to make C# more concise and accessible, it looks like this will be the default template. You can always <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/top-level-templates?ref=daveabrock.com#use-the-old-program-style">use the "old" program style</a> from the terminal using <code>framework</code> and <code>target-framework-override</code> flags. This allows you to use the "old" template but force the project framework to be .NET 6.0. (It would have been simpler to pass in <code>--leave-my-stuff-alone</code>, but I digress.)</p><pre><code class="language-bash">dotnet new console --framework net5.0 --target-framework-override net6.0</code></pre><p>In terms of the tooling experience, the obvious answer will be to eventually introduce a checkbox in Visual Studio to enable/disable these simplified layouts. Until then, you can <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/top-level-templates?ref=daveabrock.com#use-the-old-program-style-in-visual-studio">downgrade the target framework moniker</a> (TFM) to <code>net5.0</code>.</p><p>If you don't like it, you can file an issue in the <a href="https://github.com/dotnet/templating?ref=daveabrock.com">dotnet/templating repo</a> (or <a href="https://github.com/dotnet/templating/issues/3654?ref=daveabrock.com">chime in on a similar issue</a>), or even <a href="https://auth0.com/blog/create-dotnet-project-template/?ref=daveabrock.com">create your own templates</a>. </p><hr><h2 id="community-spotlight-marten-v4-is-now-live">Community spotlight: Marten v4 is now live</h2><p>Do you know about Marten? It's a <a href="https://martendb.io/introduction.html?ref=daveabrock.com">popular .NET library</a> that allows you to use Postgresql as both a document database and a powerful event store. Jeremy Miller <a href="https://jeremydmiller.com/2021/10/08/marten-takes-a-giant-leap-forward-with-the-official-v4-release/?ref=daveabrock.com">wrote this week</a> about the new v4 release. Jeremy got my attention with quoting "the immortal philosopher Ferris Bueller" but also highlighted the massive changes: </p><ul><li>Reducing object allocations and dictionary lookups</li><li>LINQ support improvements</li><li>Better tracking for flexible metadata</li><li>Event sourcing improvements</li></ul><p>It looks to be a great release, and congrats to the team and all the great contributors. Check out <a href="https://github.com/JasperFx/Marten?ref=daveabrock.com">the GitHub repository</a> for more details about the project.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3></h3><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Windows 11 <a href="https://blogs.windows.com/windowsexperience/2021/10/04/windows-11-a-new-era-for-the-pc-begins-today?ref=daveabrock.com" rel="nofollow">has arrived</a>.</li><li>Mark Weitzel <a href="https://garywoodfine.com/how-to-implement-cross-cutting-concerns-with-mediatr-pipeline-behaviours/?ref=daveabrock.com" rel="nofollow">provides an update on the Azure REST API guidelines</a>.</li><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/announcing-the-new-azure-monitor-query-client-libraries/?ref=daveabrock.com">rolls out new Azure Monitor client libraries</a>.</li><li>Bri Achtman <a href="https://devblogs.microsoft.com/dotnet/ml-net-and-model-builder-october-updates?ref=daveabrock.com" rel="nofollow">writes about some ML.NET updates</a>.</li><li>The GitHub Advisory Database <a href="https://github.blog/2021-10-07-github-advisory-database-now-powers-npm-audit/?ref=daveabrock.com">now powers</a> <code>npm audit</code>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Last week was an eventful week for the .NET Foundation. I'm not going to rehash all the events—you can read <a href="https://github.com/dotnet-foundation/Home/discussions/38?ref=daveabrock.com#discussioncomment-1445759">a thread on the issues</a>, now former Executive Director Claire Novotny's <a href="https://github.com/dotnet-foundation/Home/discussions/39?ref=daveabrock.com">apology</a>, the comments surrounding it, and the announcement of a <a href="https://github.com/dotnet-foundation/Home/discussions/40?ref=daveabrock.com">change in leadership</a>. Let's hope we see <em>structural </em>changes, and don't unfairly scapegoat another invaluable member of the .NET community.</li><li>Myles Borins <a href="https://github.blog/2021-10-04-beta-github-releases-improving-release-experience/?ref=daveabrock.com" rel="nofollow">announces a new public beta of GitHub Releases</a>.</li><li>DaprCon is a thing <a href="https://blog.dapr.io/posts/2021/10/05/join-us-for-daprcon-october-19th-20th-2021/?ref=daveabrock.com" rel="nofollow">and is happening next week</a>.</li><li>For community standups: .NET MAUI <a href="https://www.youtube.com/watch?v=cEoSkHZlKa4&ref=daveabrock.com">talks about Hot Reload</a>, EF talks about <a href="https://www.youtube.com/watch?v=2aCgKM41NFw&ref=daveabrock.com">SQL Server temporal tables and EF Core 6</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=1JnshGlNoBg&ref=daveabrock.com">updates us on Orchard Core</a>.</li><li>The Netflix Blog writes about how they <a href="https://netflixtechblog.com/safe-updates-of-client-applications-at-netflix-1d01c71a930c?ref=daveabrock.com">safely update client applications</a>.</li><li>Community releases: Marten v4 <a href="https://jeremydmiller.com/2021/10/08/marten-takes-a-giant-leap-forward-with-the-official-v4-release/?ref=daveabrock.com">is now live</a>, Blazored Toast v3.2 <a href="https://twitter.com/BlazoredTweets/status/1446547399229550595?ref=daveabrock.com">is released</a>, and <a href="https://cakebuild.net/blog/2021/10/cake-v1.3.0-released?ref=daveabrock.com">Cake v1.3.0 is out</a>.</li><li>FluentValidation <a href="https://twitter.com/JeremySkinner/status/1446086365767217152?ref=daveabrock.com">has reached 100 million downloads</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>David Walsh <a href="https://davidwalsh.name/css-accent-color?ref=daveabrock.com" rel="nofollow">writes about the accent-color CSS property</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/10/04/implement-a-secure-api-and-a-blazor-app-in-the-same-asp-net-core-project-with-azure-ad-authentication/?ref=daveabrock.com" rel="nofollow">implements a secure API and a Blazor app in the same ASP.NET Core project with Azure AD authentication</a>.</li><li>Litan Sarker <a href="https://www.c-sharpcorner.com/article/developing-a-web-app-using-angular-12-asp-net-core-web-api-and-sql-server/?ref=daveabrock.com" rel="nofollow">develops a web app with Angular 12, ASP.NET Core Web API, and SQL Server</a>.</li><li>Mike Brind <a href="https://www.mikesdotnetting.com/article/357/razor-pages-startup-in-net-6?ref=daveabrock.com" rel="nofollow">writes about the Razor Pages startup experience in .NET 6</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/aspnet-core-diagnostic-scenarios?ref=daveabrock.com" rel="nofollow">writes about Microsoft's guidance on ASP.NET Core diagnostic scenarios</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/10/01/azure-functions-4-preview.aspx?ref=daveabrock.com" rel="nofollow">writes about Azure Functions support for .NET 6</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-4-building-a-middleware-pipeline-with-webapplication/?ref=daveabrock.com" rel="nofollow">builds a middleware pipeline with WebApplication</a>.</li><li>Nwose Lotanna Victor writes about <a href="https://www.telerik.com/blogs/things-developers-do-affect-web-app-load-time?ref=daveabrock.com">things developers do</a> to affect web app load time.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Matthew Jones <a href="https://swimburger.net/blog/dynamics/delaying-javascript-execution-until-html-elements-are-present-in-power-apps-and-dynamics-crm?ref=daveabrock.com" rel="nofollow">writes about DateOnly and TimeOnly in .NET 6</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/entity-framework-core-connectionstrings-for-dotnet-apps?ref=daveabrock.com" rel="nofollow">walks through EF Core ConnectionStrings</a>.</li><li>The Code Maze blog <a href="https://code-maze.com/dotnet-code-coverage/?ref=daveabrock.com" rel="nofollow">writes about code coverage in .NET</a>.</li><li>David McCarter <a href="https://www.c-sharpcorner.com/article/everything-that-every-net-developer-needs-to-know-about-disposable-types-prop/?ref=daveabrock.com" rel="nofollow">writes about properly disposing of objects in .NET</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/differences-between-hashtable-vs-dictonary-vs-concurrentdictionary-vs-immutabledictionary?ref=daveabrock.com" rel="nofollow">writes about the differences between Hashtable, Dictionary, ConcurrentDictionary, and ImmutableDictionary</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>The Microsoft Cloud Show <a href="https://www.microsoftcloudshow.com/podcast/Episodes/429-Azure-App-Configuration/?ref=daveabrock.com" rel="nofollow">talks about Azure App Configuration</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dynamics/collaborating-on-power-apps-using-personal-environments-power-platform-cli-git-and-azure-devops?ref=daveabrock.com" rel="nofollow">collaborates on Power Apps using personal environments, Power Platform CLI, Git, and Azure DevOps</a>.</li><li>Justin Yoo writes about <a href="https://dev.to/azure/6-ways-azure-functions-endpoints-auth-via-openapi-4j0d?ref=daveabrock.com">different ways to integrate Azure Functions auth with OpenAPI</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Elijah Manor <a href="https://elijahmanor.com/byte/js-fill-array?ref=daveabrock.com" rel="nofollow">quickly populates a new array in JavaScript</a>.</li><li>Dave Brock <a href="https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/" rel="nofollow">works with file-scoped namespaces in C# 10</a>.</li><li>Assis Zang <a href="https://www.telerik.com/blogs/6-tips-writing-elegant-csharp-code?ref=daveabrock.com" rel="nofollow">has 6 tips for writing elegant C# code</a>.</li><li>Joël Quenneville asks: <a href="https://thoughtbot.com/blog/who-is-empowered-by-your-design?ref=daveabrock.com">who is empowered by your API design</a>?</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Peter Vogel <a href="https://www.telerik.com/blogs/unit-testing-legacy-applications-dealing-legacy-code-justmock?ref=daveabrock.com" rel="nofollow">uses JustMock to unit test legacy applications</a>.</li><li>Steven J. Vaughan-Nichols <a href="https://thenewstack.io/the-latest-owasp-top-10-looks-a-lot-like-the-old-owasp/?ref=daveabrock.com" rel="nofollow">writes about the refresh of the OWASP Top 10</a>.</li><li>Dennis Martinez <a href="https://www.telerik.com/blogs/top-challenges-automated-end-to-end-testing?ref=daveabrock.com" rel="nofollow">writes about challenges with automated end-to-end testing</a>.</li><li>Sam Scott and Graham Neray <a href="https://stackoverflow.blog/2021/10/06/best-practices-for-authentication-and-authorization-for-rest-apis/?ref=daveabrock.com" rel="nofollow">write about best practices for authentication and authorization for REST APIs</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/cleancodetips/use-same-name-for-same-concept?ref=daveabrock.com" rel="nofollow">offers a clean code tip</a>.</li><li>Sarah Drasner <a href="https://leaddev.com/culture-engagement-motivation/why-flow-matters-more-passion?ref=daveabrock.com" rel="nofollow">writes about why flow matters more than passion</a>.</li><li>Derek Comartin writes about his <a href="https://codeopinion.com/my-top-patterns-for-event-driven-architecture/?ref=daveabrock.com">top patterns for event-driven architecture</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and videos</h3><ul><li>Adventures in .NET <a href="https://adventuresindotnet.com/want-to-pair-up-net-089?ref=daveabrock.com" rel="nofollow">talk about pair programming</a> and also <a href="https://adventuresindotnet.com/advocate-for-yourself-part-2-net-088?ref=daveabrock.com" rel="nofollow">continues the discussion on advocating for yourself</a>.</li><li>Jesse Liberty <a href="https://jesseliberty.com/2021/10/07/mads-torgersen-on-c-10/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+JesseLiberty-SilverlightGeek+%28Jesse+Liberty%29">talks to Mads Torgersen about C# 10</a>.</li><li>The .NET Core Show talks to Carl-Hugo Marcotte <a href="https://dotnetcore.show/episode-84-asp-net-core-5-design-patterns-with-carl-hugo-marcotte/?ref=daveabrock.com">about ASP.NET Core 5 design patterns</a>.</li><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Solution-Filters-in-Visual-Studio?ref=daveabrock.com" rel="nofollow">discusses Solution Filters in Visual Studio</a>.</li><li>On .NET talks about <a href="https://www.youtube.com/watch?v=yVd7vbeFj-g&ref=daveabrock.com">using DynamicData</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #65: 💡 Is there hope for a modern C# model? ]]></title>
        <description><![CDATA[ This week, we explore the question: will we ever see a sleeker &quot;modern C#&quot; language subset? ]]></description>
        <link>https://www.daveabrock.com/2021/10/10/dotnet-stacks-65/</link>
        <guid isPermaLink="false">61587c23069a18003d6d3d79</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 10 Oct 2021 11:33:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/10/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday to you all and happy October. I hope you have a good week. My goal: to develop a data model <a href="https://developer.apple.com/documentation/contacts/cnlabelcontactrelationyoungercousinmotherssiblingsdaughterorfatherssistersdaughter?ref=daveabrock.com">simpler than this one</a>.</p><p>Here's what we have this week:</p><ul><li>Exploring modern C#</li><li>Custom deployment layouts for Blazor WebAssembly apps</li><li>Last week in the .NET world</li></ul><hr><h2 id="exploring-modern-c">Exploring modern C#</h2><p>With the official release of .NET 6 next month, we'll see the release of C# 10. Much like the .NET platform as a whole, the language is beginning to adopt incremental, annual releases going forward. The <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10?ref=daveabrock.com">C# 10 release brings us</a> features like record structs, global using directives, extended property patterns, file-scoped namespaces, and so on. Richard Lander's .NET 6 RC2 announcement will be looking into some of these. </p><p>As C# has shifted over the years from a strict OO language to a more general-purpose one, it's experienced some pushback on how heavy it's become. We tend to go in circles in the .NET community: yes, there's a lot—it needs to evolve to be a modern language, but it also can't break people who rely on the older features. Right on time, the newsletter Twitter account <a href="https://twitter.com/dotnetstacks/status/1443334774500859914?ref=daveabrock.com">posted a link</a> to an article asking: is C# too complex? It spawned an interesting discussion, both about the article itself and of C#.</p><p>I like what Kathleen Dollard, a Microsoft PM for .NET Core CLI and Languages, had to say:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">It seems you can have 2 of the 3: language evolution, backwards compat, one way to do things.<br><br>Would you give up the simplicity of var or the simplification possible with tuples for a single way to do things?</p>&mdash; Kathleen Dollard (@KathleenDollard) <a href="https://twitter.com/KathleenDollard/status/1443358768616509445?ref_src=twsrc%5Etfw&ref=daveabrock.com">September 29, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Still, I don't think it's realistic to expect a single way to do things, but it can get out of hand. As a simple example, there are at least a half dozen ways to check if a string is empty. It's that there are so many ways to do a single thing: some are modern and some best practices, some not—all the while, we know the language will never take anything away for backward compatibility reasons. </p><p>For us experienced developers, we can say the language is evolving and just "use what works best for you." What if you don't, or don't want the mental weight of dealing with it all?</p><p>As I was listening to C# language designer Mads Torgersen <a href="https://nodogmapodcast.bryanhogan.net/157-mads-torgersen-c-10-part-1/?ref=daveabrock.com">on Bryan Hogan's <em>No Dogma</em> podcast</a>, I found this following exchange quite interesting. (I know there's a lot in this exchange, but I wanted to post it all to avoid taking anything out of context.)</p><blockquote>Q: <strong>All of these new features, feel like new ways of doing old things and I would imagine they could get confusing. A criticism about C# that's been around for a while is that there are so many ways to do one thing anyway, and now you've added a whole bunch of new ways to do things I could do already.</strong></blockquote><blockquote>A: Yes. That's a real challenge. If you have a programming language and you want to keep it the best option for somebody making the next project, it has to be modern. It has to have ways of doing things that are as expressive, as sleek,  as ergonomic, performant, fast, and efficient as the other languages. So we have to keep evolving to do that. Now at the same time, we don't like throwing things out because we break people's existing code. What's a programming language designer to do?</blockquote><blockquote>We've lived with this conundrum for a while. I think we're starting to circle in on at least a partial solution to it. I can't say for sure that we're going to do this or how we're going to do it, but ... someone like Bill Wagner, who is doing our documentation and working on the C# Standard ...he's very essential in this discussion, said: "How about we try to define modern C#?" If you're coming to C# fresh or even as an existing C# programmer in general—if you have a pretty clean slate, this is the subset that you should be using. If you're outside of that subset it's either because you're trying something fancy like using <code>Span&lt;T&gt;</code> to do efficiency stuff or unsafe code, or it's because you're doing some legacy things. Otherwise, these are the ways you should be doing things. </blockquote><blockquote>And then we could reinforce that from the documentation point of view, from a learning point of view, and also from a tooling point of view—we would take these templates and take those little suggestions and say: "Hey, that's kind of an old fashioned thing you're doing there, it would be sleeker to use pattern matching here, why don't you?" In fact, we have plenty of those in place already. We just don't have a coordinated set of features that are like "this is modern C#." </blockquote><blockquote>Then that evolves with the language, like when usings come in and some other things fall out of what modern C# is. And now there's a better way to do things. Now, we don't tell you to put usings on top of the file anymore, and we don't have guidelines about whether to prune or not ... that's just gone out of modern C# and now a modern C# programmer doesn't do that anymore.  A sliding window that's current C# might help as long as we don't make it a worse experience to use all of the language. But maybe we can make it an even better experience to use the modern part of the language and can give you more guidance if you're not a veteran or if you don't want to chase down all the reasons for doing one or the other and you just want a recommendation—how should I be doing this? This is what we're currently working on.</blockquote><p>I found this very interesting. A C# subset is not a new idea but I think Microsoft working on it is. In the past, I've seen some Microsoft resistance to that idea. It's early days but promising for the future of C#.</p><hr><h2 id="custom-deployment-layouts-for-blazor-web-assembly-apps">Custom deployment layouts for Blazor Web Assembly apps</h2><p>This week, on the ASP.NET Blog, Javier Calvarro Nelson <a href="https://devblogs.microsoft.com/aspnet/custom-deployment-layout-for-blazor-webassembly-apps/?ref=daveabrock.com">wrote about new .NET 6 extensibility points</a> that will allow development teams to customize which files to package and publish with Blazor WebAssembly apps. The idea is that you could reuse this as a NuGet package. As Javier notes, this is important because some environments block and download the execution of DLLs from the network for security reasons.</p><p>The article lays out how to build the package yourself, but you don't have to. According to Daniel Roth, you can use a <a href="https://www.nuget.org/packages/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle?ref=daveabrock.com">prebuilt experimental NuGet package</a> to try it out. To use it, <a href="https://devblogs.microsoft.com/aspnet/custom-deployment-layout-for-blazor-webassembly-apps/?ref=daveabrock.com#using-the-multipartbundle-package">add a reference from your client project, update the server project to add the endpoint, and then publish your app</a>. This is a good first step—hopefully, the end goal is to provide this out of the box. </p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3></h3><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Michael Staib <a href="https://chillicream.com/blog/2021/09/27/hot-chocolate-12?ref=daveabrock.com" rel="nofollow">releases Hot Chocolate 12</a>.</li><li>Jiachen Jiang <a href="https://devblogs.microsoft.com/nuget/introducing-the-new-nuget-org-package-details-page?ref=daveabrock.com" rel="nofollow">writes about the new nuget.org package details page</a>.</li><li>JetBrains launches <a href="https://blog.jetbrains.com/dotnet/2021/09/28/resharper-2021-3-eap/?ref=daveabrock.com" rel="nofollow">the EAP for Resharper 2021.3</a> and also for <a href="https://blog.jetbrains.com/dotnet/2021/09/28/rider-2021-3-eap/?ref=daveabrock.com" rel="nofollow">Rider 2021.3</a>.</li><li>Javier Calvarro Nelson writes about <a href="https://devblogs.microsoft.com/aspnet/custom-deployment-layout-for-blazor-webassembly-apps?ref=daveabrock.com" rel="nofollow">custom deployment layouts for Blazor WebAssembly apps</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Rodney Littles II writes a difficult, but important, post about <a href="https://rodneylittlesii.com/posts/topic/foundation-echo-chamber?ref=daveabrock.com">his experience on the .NET Foundation board</a>.</li><li>Carol Smith <a href="https://cloudblogs.microsoft.com/opensource/2021/09/28/announcing-azure-credits-for-open-source-projects?ref=daveabrock.com" rel="nofollow">announces Azure credits for open source projects</a>.</li><li>Beau Carnes <a href="https://www.freecodecamp.org/news/git-for-professionals/?ref=daveabrock.com" rel="nofollow">launches a free Git for Professionals course</a>.</li><li>Henning Dieterichs <a href="https://code.visualstudio.com/blogs/2021/09/29/bracket-pair-colorization?ref=daveabrock.com" rel="nofollow">writes about how the VS Code team made bracket pair colorization 1000x faster</a>.</li><li>Austin Lamb introduces <a href="https://devblogs.microsoft.com/performance-diagnostics/sizebench-a-new-tool-for-analyzing-windows-binary-size?ref=daveabrock.com" rel="nofollow">SizeBench, a new tool for analyzing Windows binary size</a>.</li><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/09/28/efficient-web-services-with-marten-v4/?ref=daveabrock.com" rel="nofollow">writes about how to build efficient web services with Marten v4</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Kristoffer Strube <a href="https://blog.elmah.io/ahead-of-time-compilation-for-blazor-wasm/?ref=daveabrock.com" rel="nofollow">uses Blazor AoT compilation</a>.</li><li>Jon Hilton <a href="https://jonhilton.net/blazor-component-folder-structure/?ref=daveabrock.com" rel="nofollow">writes about how he organizes his Blazor components</a>.</li><li>Nancy Young <a href="https://www.webdesignerdepot.com/2021/09/the-pros-and-cons-of-tailwind-css/?ref=daveabrock.com" rel="nofollow">writes about the pros and cons of Tailwind</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-3-exploring-the-code-behind-webapplicationbuilder/?ref=daveabrock.com" rel="nofollow">explores the code behind WebApplicationBuilder in .NET 6</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Tomasz Pęczek <a href="https://www.tpeczek.com/2021/09/handling-transient-errors-in-durable.html?ref=daveabrock.com" rel="nofollow">handles transient errors in Azure Durable Functions</a>.</li><li>Mark Heath <a href="https://markheath.net/post/azure-functions-isolated?ref=daveabrock.com" rel="nofollow">asks: is it time to start creating C# Azure Functions in isolated mode?</a>.</li><li>Steve Smith <a href="https://ardalis.com/github-actions-on-demand/?ref=daveabrock.com" rel="nofollow">writes about running GitHub Actions on demand</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Michael Moreno asks: <a href="https://medium.com/nerd-for-tech/is-c-getting-too-complicated-for-its-own-good-83c149a6faca?ref=daveabrock.com" rel="nofollow">is C# getting too complex?</a></li><li>Vladimir Pecanac <a href="https://code-maze.com/csharp-events/?ref=daveabrock.com" rel="nofollow">explores events in C#</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/implicit-usings-in-net-6?ref=daveabrock.com" rel="nofollow">writes about implicit usings in .NET 6</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/compress-strings-with-dotnet-and-csharp?ref=daveabrock.com" rel="nofollow">compresses strings with .NET and C#</a>.</li><li>Jeff Fritz <a href="https://www.youtube.com/watch?v=sfe8UX9b9xM&ref=daveabrock.com" rel="nofollow">introduces LINQ in C#</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/09/30/c-10-global-using-directives/?ref=daveabrock.com" rel="nofollow">uses global using directives in C# 10</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>The Kubernetes Blog <a href="https://kubernetes.io/blog/2021/09/29/how-to-handle-data-duplication-in-data-heavy-kubernetes-environments/?ref=daveabrock.com" rel="nofollow">discusses how to handle data duplication</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/testing-httpclientfactory-moq?ref=daveabrock.com" rel="nofollow">tests HttpClientFactory with Moq</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/09/24/github-copilot-alternatives.aspx?ref=daveabrock.com" rel="nofollow">writes how GitHub Copilot AI is spawning OSS Alternatives</a>.</li><li>Christian Gunderman <a href="https://devblogs.microsoft.com/visualstudio/avoiding-memory-leaks-in-visual-studio-editor-extensions?ref=daveabrock.com" rel="nofollow">avoids memory leaks in Visual Studio editor extensions</a>.</li><li>Mike Melanson <a href="https://thenewstack.io/docker-defends-desktop-pricing-says-support-led-to-faster-features/?ref=daveabrock.com" rel="nofollow">writes about Docker defending their new Docker Desktop pricing</a>, and the Docker Desktop <a href="https://www.docker.com/blog/looking-for-a-docker-alternative-consider-this/?ref=daveabrock.com" rel="nofollow">PR campaign continues</a>.</li><li>Tobias Günther <a href="https://css-tricks.com/creating-the-perfect-commit-in-git/?ref=daveabrock.com" rel="nofollow">creates the perfect commit in Git</a>.</li><li>Milan Milanović <a href="https://milan.milanovic.org/post/cd-cd-with-azure-devops-yaml/?ref=daveabrock.com" rel="nofollow">writes about CI/CD with Azure DevOps</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Derek Comartin <a href="https://codeopinion.com/always-valid-domain-model/?ref=daveabrock.com" rel="nofollow">talks about an always valid domain model</a>.</li><li>Steve Smith <a href="https://ardalis.com/grouping-assertions-in-tests/?ref=daveabrock.com" rel="nofollow">groups assertions in tests</a>.</li><li>Thomas Maurer <a href="https://github.blog/2021-09-27-partitioning-githubs-relational-databases-scale/?ref=daveabrock.com" rel="nofollow">writes about how GitHub partitions its relational databases</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-encapsulating-collections?ref=daveabrock.com" rel="nofollow">continues his DDD series with a write-up on encapsulating collections</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/unit-testing-legacy-code-part-2-leveraging-mock-objects?ref=daveabrock.com" rel="nofollow">continues his series on unit testing legacy code</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and videos</h3><ul><li>The Coding Blocks Podcast talks about <a href="https://www.codingblocks.net/podcast/transactions-in-distributed-systems/?ref=daveabrock.com" rel="nofollow">transactions in distributed systems</a>.</li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1759&ref=daveabrock.com" rel="nofollow">talks to Mark Seemann about code that fits in your head</a>.</li><li>Software Engineering Daily <a href="https://softwareengineeringdaily.com/2021/09/30/git-scales-for-monorepos-with-derrick-stolee/?ref=daveabrock.com" rel="nofollow">talks about scaling Git for monorepos</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=c0VwTzQ2gUQ&ref=daveabrock.com" rel="nofollow">discuss new LINQ methods in .NET 6</a>.</li><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Azure-Cosmos-DB-autoscale-session-state-monitoring-and-more?ref=daveabrock.com" rel="nofollow">walks through CosmosDB</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/azure-sql-database-with-anna-hoffman-episode-160?ref=daveabrock.com" rel="nofollow">talks to Anna Hoffman about Azure SQL</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Exploring C# 10: Save Space with File-Scoped Namespaces ]]></title>
        <description><![CDATA[ In this post, let&#39;s explore file-scoped namespaces in the new version of C#, C# 10. ]]></description>
        <link>https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/</link>
        <guid isPermaLink="false">615bb50f069a18003d6d401a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 04 Oct 2021 22:35:27 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1527515637462-cff94eecc1ac?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNsZWFufGVufDB8fHx8MTYzMzQwMTY3MA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>.NET 6 and C# 10 hit general availability <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10?ref=daveabrock.com">next month</a> (in November 2021). Much like I did <a href="https://www.daveabrock.com/tag/csharp-9-2/">with C# 9 last year</a>, I'd like to write about C# 10 over my next few posts. First, let's talk about a simple yet powerful capability: file-scoped namespace declarations. </p><p>If you're new to C# and aren't familiar with what namespaces are, you can use a <code>namespace</code> keyword to declare scopes that contain a set of related objects. What kind of objects? According to <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace?ref=daveabrock.com">the Microsoft documentation</a>, namespaces can have classes, interfaces, enums, structs, or delegates. By default, the C# compiler adds a default, unnamed namespace for you—typically referred to as the global namespace. When you declare a specific namespace, you can use identifiers present in the global namespace. See <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace?ref=daveabrock.com">the C# docs</a> for details.</p><p>So, how can you declare namespaces in C# 9 and earlier? Keeping with my superhero theme with <a href="https://www.daveabrock.com/tag/csharp-9-2/">my C# 9 posts</a>, a <code>Superhero.cs</code> class would look like this:</p><pre><code class="language-csharp">using System;

namespace SuperheroApp.Models
{
   public class Superhero
   {
      public string? FirstName { get; set; }
      public string? LastName { get; set; }
      public string? StreetAddress { get; set; }
      public string? City { get; set; }
      public int? MaxSpeed { get; set; }
   }
}</code></pre><p>Even with this simple example, you can see how much space this adds—both horizontally and vertically—with the indents and curly braces. With C# 10, you can make this cleaner with file-scoped namespaces.</p><h2 id="use-c-10-file-scoped-namespaces-to-simplify-your-code">Use C# 10 file-scoped namespaces to simplify your code</h2><p>With C# 10, you can remove the curlies and replace it with a semicolon, like this:</p><pre><code class="language-csharp">namespace SuperheroApp.Models;

public class Superhero
{
   public string? FirstName { get; set; }
   public string? LastName { get; set; }
   public string? StreetAddress { get; set; }
   public string? City { get; set; }
   public int? MaxSpeed { get; set; }
}</code></pre><p>If you have <code>using</code> statements in your file, you can have the namespace declaration either before or after it. However, it must come before any other members in a file, like your classes or interfaces. Many code analyzers like StyleCop <a href="https://documentation.help/StyleCop/SA1200.html?ref=daveabrock.com">encourage the use of usings inside namespaces</a> to avoid type confusion.</p><p>It's worth noting that as the "file-scoped" naming implies, this applies to any objects in the file—like classes, interfaces, structs, and so on. Also, you are limited to only defining one file-scoped namespace per file. You likely aren't surprised, as most of your files typically only have a single namespace.</p><h2 id="limitations-with-file-scoped-namespaces">Limitations with file-scoped namespaces</h2><p>Now, let's review what you cannot do with file-scoped namespaces. </p><h3 id="mix-traditional-namespaces-and-file-scoped-namespaces">Mix traditional namespaces and file-scoped namespaces</h3><p>If you want to mix a non-C# 10 namespace declaration and a file-scoped namespace, you can't. Here's what you'll see from Visual Studio.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/image.png" class="kg-image" alt loading="lazy" width="1103" height="214" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/image.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/10/image.png 1000w, https://www.daveabrock.com/content/images/2021/10/image.png 1103w" sizes="(min-width: 720px) 720px"></figure><h3 id="define-multiple-file-scoped-namespaces">Define multiple file-scoped namespaces</h3><p>What if you want multiple namespaces in a file like this?</p><pre><code class="language-csharp">namespace SuperheroApp.Models;

public class Superhero
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? StreetAddress { get; set; }
    public string? City { get; set; }
    public int? MaxSpeed { get; set; }
}

namespace SuperheroApp.Models.Marvel;

public class MarvelSuperhero : Superhero
{
    public string[] MoviesIn { get; set; }
}</code></pre><p>As discussed previously, you can only define one file-scoped namespace per file. It won't work.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/multiple-fs-namespaces-1.png" class="kg-image" alt loading="lazy" width="935" height="648" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/multiple-fs-namespaces-1.png 600w, https://www.daveabrock.com/content/images/2021/10/multiple-fs-namespaces-1.png 935w" sizes="(min-width: 720px) 720px"></figure><p>If you want to accomplish this, you'll need to stay old school and define namespace declarations as you usually have.</p><pre><code class="language-csharp">namespace SuperheroApp.Models
{
    public class Superhero
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
        public string? StreetAddress { get; set; }
        public string? City { get; set; }
        public int? MaxSpeed { get; set; }
    }
}

namespace SuperheroApp.Models.Marvel
{
    public class MarvelSuperhero : Superhero
    {
        public string[] MoviesIn { get; set; }
    }
}</code></pre><h3 id="nesting-namespaces">Nesting namespaces</h3><p>With traditional namespaces, you can nest them like in the following example.</p><pre><code class="language-csharp">namespace SuperheroApp.Models
{
    public class Superhero
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
        public string? StreetAddress { get; set; }
        public string? City { get; set; }
        public int? MaxSpeed { get; set; }
    }

    namespace SuperheroApp.Models.Marvel
    {
        public class MarvelSuperhero : Superhero
        {
            public string[] MoviesIn { get; set; }
        }
    }
}</code></pre><p>However, you can not do this with file-scoped namespaces. When I try to do this, I'll get another compiler error.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/10/nested-namespaces.png" class="kg-image" alt loading="lazy" width="1093" height="632" srcset="https://www.daveabrock.com/content/images/size/w600/2021/10/nested-namespaces.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/10/nested-namespaces.png 1000w, https://www.daveabrock.com/content/images/2021/10/nested-namespaces.png 1093w" sizes="(min-width: 720px) 720px"></figure><h2 id="wrapping-up-another-way-to-simplify-c-code">Wrapping up: another way to simplify C# code</h2><p>If you've been following the last couple of C# releases, you've noticed this isn't the first change to simplify boilerplate code—see positional C# records and top-level statements for a few examples—and it likely won't be the last, either. Changes like this allow you to simplify your programs and cut out boilerplate.</p><p>In the next post, I'll continue this theme by writing about <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10?ref=daveabrock.com#global-using-directives">global using directives</a> in C# 10. I'll talk to you then.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #64: ⚡ Looking at Functions support in .NET 6 ]]></title>
        <description><![CDATA[ This week, we get a closer look at Azure Functions support for .NET 6. ]]></description>
        <link>https://www.daveabrock.com/2021/10/03/dotnet-stacks-64/</link>
        <guid isPermaLink="false">615083d9f55adf003bbe52fd</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 03 Oct 2021 11:26:27 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/09/THE-.NET-STACKS-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another week. I hope you had a good weekend. Before getting to the community links, I've got some quick items for you this week:</p><ul><li>Azure Functions .NET 6 support</li><li>.NET Foundation Board election news</li><li>Syncing namespaces in Visual Studio</li><li>Last week in the .NET world</li></ul><hr><h2 id="azure-functions-net-6-support">Azure Functions .NET 6 support</h2><p>Last week, Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/announcing-azure-functions-4-0-public-preview-with-net-6-support/ba-p/2772098?ref=daveabrock.com">announced the availability of the public preview for Azure Functions 4.0</a>—which includes .NET 6 support. In case you weren't aware, Azure Functions has two programming models: in-process and isolated. Azure Functions 4.0 supports .NET 6 through the isolated model. </p><p>As Anthony states, the isolated model gives you greater control over Functions configuration and allows you to use DI and middleware as you do in your ASP.NET Core apps. Currently, you can only use this from CLI tooling. Soon, there will be support for Visual Studio and Visual Studio closer to the general .NET 6 release date in November (which is when Azure Functions 4.0 will be off public preview and generally available).</p><p>Since we're talking about Azure Functions, long-term the in-process model will be retired in favor of the isolated model. As you can see from this diagram I stole from Microsoft, that won't happen until .NET 7 in November 2022.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/09/image-6.png" class="kg-image" alt loading="lazy" width="998" height="340" srcset="https://www.daveabrock.com/content/images/size/w600/2021/09/image-6.png 600w, https://www.daveabrock.com/content/images/2021/09/image-6.png 998w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="net-foundation-board-election-news">.NET Foundation Board election news</h2><p>The results are out for the <a href="https://dotnetfoundation.org/blog/2021/09/22/net-foundation-election-results-2021?ref=daveabrock.com">2021 .NET Foundation Board elections</a>. Congratulations to the following folks who made the cut:</p><ul><li>Mattias Karlsson</li><li>Frank Odoom</li><li>Rob Prouse</li><li>Javier Lozano (<em>re-elected</em>) </li></ul><hr><h2 id="syncing-namespaces-in-visual-studio">Syncing namespaces in Visual Studio</h2><p>As <a href="https://twitter.com/okyrylchuk/status/1440419281603235842?ref=daveabrock.com">Oleg Kyrylchuk mentions</a>, in the last preview of Visual Studio 2022 you can syncronize namespaces to mirror how the folder structure looks in Solution Explorer. This is in preview, but looks to be a cool feature—and should be done with caution, as there isn't currently a way to undo easily.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the last preview of Visual Studio 2022, you can synchronize namespaces to match your folder structure from Solution Explorer.<a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://twitter.com/hashtag/coding?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#coding</a> <a href="https://twitter.com/hashtag/devcommunity?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#devcommunity</a> <a href="https://t.co/fJ3zhkc5bf?ref=daveabrock.com">pic.twitter.com/fJ3zhkc5bf</a></p>&mdash; Oleg Kyrylchuk (@okyrylchuk) <a href="https://twitter.com/okyrylchuk/status/1440419281603235842?ref_src=twsrc%5Etfw&ref=daveabrock.com">September 21, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Grace Taylor <a href="https://devblogs.microsoft.com/visualstudio/custom-themes?ref=daveabrock.com" rel="nofollow">announces a collection of VS themes</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/09/22/net-foundation-election-results-2021?ref=daveabrock.com" rel="nofollow">election results are in</a>.</li><li>On September 30 <a href="https://docs.microsoft.com/en-us/events/learntv/lets-learn-dotnet-iot-sept-2021?ref=daveabrock.com" rel="nofollow">Microsoft will be hosting a "Let's Learn .NET" on IoT</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-september-2021?ref=daveabrock.com" rel="nofollow">recaps the September release</a>.</li><li>Steve Smith <a href="https://ardalis.com/dependency-injection-book-review/?ref=daveabrock.com" rel="nofollow">reviews a new DI book</a>.</li><li>Josef Ottosson <a href="https://josef.codes/jos-configuration-convenient-methods-for-configuration-in-dotnet-core/?ref=daveabrock.com" rel="nofollow">created a library that packages convenient configuration methods in .NET Core</a>.</li><li>For community standups, Desktop <a href="https://www.youtube.com/watch?v=DjNf_EfccAc&ref=daveabrock.com">talks about Hot Reload updates</a>, EF <a href="https://www.youtube.com/watch?v=Ya_cmZRwACM&ref=daveabrock.com">talks about PostgreSQL and EF Core</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=hVdwb41FPvU&ref=daveabrock.com">talks about how to contribute to the platform</a>.</li><li>The .NET Docs show talks about <a href="https://www.youtube.com/watch?v=KlP5ofXhu-c&ref=daveabrock.com">home automation with Azure Precept</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Nigel Sampson <a href="https://compiledexperience.com/blog/posts/crosscutting-grapql?ref=daveabrock.com" rel="nofollow">adds cross-cutting concerns to a GraphQL service</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/code-snippet-conditional-user-agent-logic-with-blazor?ref=daveabrock.com" rel="nofollow">wires up conditional User-Agent logic with Blazor</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/how-to-detect-if-the-users-os-prefers-dark-mode-and-change-your-site-with-css-and-js?ref=daveabrock.com" rel="nofollow">shows how to change a site's Dark Mode based on the user's OS preference</a>, and also <a href="https://www.hanselman.com/blog/minimal-apis-in-net-6-but-where-are-the-unit-tests?ref=daveabrock.com" rel="nofollow">writes about unit testing Minimal APIs in .NET 6</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/09/22/asp-net-core-6-streaming-json-responses-with-iasyncenumerable-example-with-angular/?ref=daveabrock.com" rel="nofollow">uses Angular and .NET 6 to stream JSON responses</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Matt Eland <a href="https://raygun.com/blog/linq-net-6-improvements/?ref=daveabrock.com" rel="nofollow">writes about LINQ .NET 6 improvements</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-2-comparing-webapplicationbuilder-to-the-generic-host/?ref=daveabrock.com" rel="nofollow">compares the WebApplicationBuilder to the generic host in .NET 6</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/interesting-technology-tips-vol-1?ref=daveabrock.com" rel="nofollow">provides some "interesting technology tips."</a></li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Muhammed Saleem <a href="https://code-maze.com/azure-table-storage-aspnetcore/?ref=daveabrock.com" rel="nofollow">works with Azure Table Storage in ASP.NET Core</a>.</li><li>Abhishek Gupta <a href="https://dev.to/azure/enhance-local-development-experience-using-the-azure-cosmos-db-linux-emulator-and-vs-code-1kce?ref=daveabrock.com" rel="nofollow">uses the Azure Cosmos DB Linux emulator and VS Code</a>.</li><li>Adam Storr asks: <a href="https://adamstorr.azurewebsites.net/blog/is-accessing-querystring-values-in-azure-functions-hard?ref=daveabrock.com" rel="nofollow">is accessing query string values in Azure Functions hard?</a></li><li>Cyrille Visser <a href="https://devblogs.microsoft.com/cosmosdb/getting-started-end-to-end-example-2?ref=daveabrock.com" rel="nofollow">optimizes Azure Cosmos DB queries</a>.</li><li>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/announcing-azure-functions-4-0-public-preview-with-net-6-support/ba-p/2772098?ref=daveabrock.com" rel="nofollow">announces Azure Functions 4.0 public preview with .NET 6 support</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/09/20/creating-microsoft-teams-meetings-in-asp-net-core-using-microsoft-graph/?ref=daveabrock.com" rel="nofollow">creates Microsoft Teams meetings in ASP.NET Core using Microsoft Graph</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Ian Griffiths <a href="https://endjin.com/blog/2021/09/dotnet-csharp-10-implicit-global-using-directives.html?ref=daveabrock.com" rel="nofollow">writes about implicit global using directives in C# 10</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/csharptips/using-alias?ref=daveabrock.com" rel="nofollow">uses aliases in C#</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/09/21/c-10-file-scoped-namespaces/?ref=daveabrock.com" rel="nofollow">writes about file-scoped namespaces in C# 10</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Michael Shpilt <a href="https://michaelscodingspot.com/performance-tools-dotnet/?ref=daveabrock.com" rel="nofollow">writes about 6 tools to detect and fix performance issues in .NET</a>.</li><li>Sarah Lean <a href="https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/?ref=daveabrock.com" rel="nofollow">looks at the GitHub CLI</a>.</li><li>Elijah Manor <a href="https://elijahmanor.com/byte/git-recent-branches?ref=daveabrock.com" rel="nofollow">lists recent Git branches</a>.</li><li>Jason Gaylord writes about <a href="https://www.jasongaylord.com/blog/2021/09/24/github-settings-you-may-not-have-known?ref=daveabrock.com">GitHub settings you might not know about</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/09/19/how-to-set-up-dotnet-maui-on-windows/?ref=daveabrock.com" rel="nofollow">sets up .NET MAUI on Windows</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/getting-device-information-with-xamarin-essentials/?ref=daveabrock.com" rel="nofollow">gets device information</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>The Netflix Tech Blog <a href="https://netflixtechblog.com/what-is-an-a-b-test-b08cc1b57962?ref=daveabrock.com" rel="nofollow">writes about A/B testing</a>.</li><li>Daniel Wertheim <a href="https://danielwertheim.se/csharp-always-valid-value-objects/?ref=daveabrock.com" rel="nofollow">writes about value objects that are always valid</a>.</li><li>Tariq Siddiqui <a href="https://www.developer.com/web-services/securing-web-apis/?ref=daveabrock.com" rel="nofollow">writes about securing web APIs</a>.</li><li>Bilgin Ibryam <a href="https://developers.redhat.com/articles/2021/09/21/distributed-transaction-patterns-microservices-compared?ref=daveabrock.com" rel="nofollow">compares distributed transaction patterns for microservices</a>.</li><li>Peter Vogel starts writing about <a href="https://www.telerik.com/blogs/unit-testing-legacy-code-part-1-creating-maintainable-applications?ref=daveabrock.com">unit testing legacy code</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/id-token-access-token-what-is-the-difference/?ref=daveabrock.com">compares ID tokens and access tokens</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and videos</h3><ul><li>AzureFunBytes talks to <a href="https://devblogs.microsoft.com/devops/azurefunbytes-episode-56-secretless-applications-with-christosmatskas?ref=daveabrock.com" rel="nofollow">Christos Matskas about secretless applications</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/joe-guadagno-on-the-latest-in-azure-devops-episode-159?ref=daveabrock.com" rel="nofollow">talks to Joe Guadagno about the latest in Azure DevOps</a>.</li><li>The Changelog <a href="https://changelog.com/podcast/460?ref=daveabrock.com" rel="nofollow">talks about the business model of open source</a>.</li><li>The Unhandled Exception Podcast <a href="https://unhandledexceptionpodcast.com/posts/0024-stevecollins/?ref=daveabrock.com" rel="nofollow">talks to Steve Collins about DI in .NET</a>.</li><li>Adventures in .NET <a href="https://devchat.tv/adventures-in-dotnet/advocate-for-yourself-net-087/?ref=daveabrock.com" rel="nofollow">talk about advocating for yourself</a>.</li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1758&ref=daveabrock.com" rel="nofollow">talks to Zaid Ajaj about F# and JS</a>.</li><li>Merge Conflict <a href="https://www.mergeconflict.fm/272?ref=daveabrock.com" rel="nofollow">recaps .NET 6 RC1, .NET MAUI updates, and more</a>.</li><li>The .NET Core Podcast talks to Davide Bedine <a href="https://dotnetcore.show/episode-83-dapr-and-dotnet-with-davide-bedine/?ref=daveabrock.com">about Dapr and .NET microservices</a>.</li><li>Jeff Fritz <a href="https://www.youtube.com/watch?v=CDfI0BldN-A&ref=daveabrock.com" rel="nofollow">walks through collections and generics in C#</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=K3TnEOA6-7s&ref=daveabrock.com" rel="nofollow">process CSV files in C#</a>.</li><li>The On .NET Show <a href="https://www.youtube.com/watch?v=7Onm8vo8bdg&ref=daveabrock.com">talks about Reaqtor</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #63: 🗞 .NET 6 is for real now ]]></title>
        <description><![CDATA[ This week, we talk all about the release of .NET 6 RC 1. ]]></description>
        <link>https://www.daveabrock.com/2021/09/26/dotnet-stacks-63/</link>
        <guid isPermaLink="false">6145e9aa440b9d003d0fdafb</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 26 Sep 2021 01:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/09/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! This week, we're talking about .NET 6 RC1 and some other topics. Oh, and if you're using Travis CI, <a href="https://arstechnica.com/information-technology/2021/09/travis-ci-flaw-exposed-secrets-for-thousands-of-open-source-projects/?ref=daveabrock.com">maybe you shouldn't</a>.</p><hr><h2 id="%F0%9F%94%A5-my-favorites-from-last-week">🔥 My favorites from last week</h2><p><a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-1/?ref=daveabrock.com">Announcing .NET 6 Release Candidate 1</a><br>Richard Lander</p><p><a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com">ASP.NET Core updates in .NET 6 Release Candidate 1</a><br>Daniel Roth</p><p><a href="https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d?ref=daveabrock.com">Migration to ASP.NET Core in .NET 6</a><br>David Fowler</p><p><a href="https://devblogs.microsoft.com/dotnet/update-on-dotnet-maui/?ref=daveabrock.com">Update on .NET Multi-platform App UI (.NET MAUI)</a><br>Scott Hunter</p><p><a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-4-is-now-available/?ref=daveabrock.com">Visual Studio 2022 Preview 4 is now available!</a><br>Mads Kristensen</p><p>As expected, .NET 6 Release Candidate (RC) 1 rolled out last week. It's the first of two RC releases deemed "go-live" ready and supported in production. .NET 6 has been feature-complete for a while now, and <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-release-candidate-1/?ref=daveabrock.com">as Richard Lander states</a>, for this release the "team has been focused exclusively on quality improvements that resolve functional or performance issues in new features or regressions in existing ones." Still, the blog post is worth a read to understand .NET 6's foundational features.</p><p>As for <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com">the ASP.NET Core side of things</a>, we're seeing quite a bit. The team is rolling out the ability to <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#render-blazor-components-from-javascript">render Blazor components from JS</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#render-blazor-components-from-javascript">Blazor custom elements</a> (on an experimental basis), the ability to <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#generate-angular-and-react-components-using-blazor">generate Angular and React components with Blazor</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#generate-angular-and-react-components-using-blazor">.NET to JavaScript streaming</a>, and <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#template-improvements">template improvements</a>—including the ability to opt-in to implicit usings—and much more.</p><p>Of course, it wouldn't be an ASP.NET Core release without talking about Minimal APIs. RC1 <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/?ref=daveabrock.com#minimal-api-updates">brings a lot of updates</a>: better support for OpenAPI for defining metadata, parameter binding improvements (like allowing optional parameters in endpoint actions), and the ability to use multiple calls to <code>UseRouting</code> to support more middleware. David Fowler also <a href="https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d?ref=daveabrock.com">dropped a nice guide</a> for migrating ASP.NET Core to .NET 6. You'll want to check it out to understand how the new hosting model works.</p><p>Have a sad trombone ready? .NET MAUI will not be making it into .NET 6's official release in November, <a href="https://devblogs.microsoft.com/dotnet/update-on-dotnet-maui/?ref=daveabrock.com">according to a Microsoft Scott</a>. It's now looking like it'll be released in early Q2 of 2022. There was a lot to be done, and a slight delay beats a buggy release any day. You can also check out Scott's post for an overview on features rolled out with .NET MAUI Preview 8.</p><p>Going hand-in-hand with the .NET 6 releases, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-4-is-now-available/?ref=daveabrock.com">Visual Studio 2022 Preview 4 is now available</a>. This release promises personal/team productivity improvements (like finding files) and thankfully a big update for the Blazor and Razor editors. You can now use VS 2022 to hot reload on file save in ASP.NET Core and also apply changes to CSS live. <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-4-is-now-available/?ref=daveabrock.com">Check out the blog post</a> for details. </p><h2 id="%F0%9F%93%A2-announcements">📢 Announcements</h2><p><a href="https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/?ref=daveabrock.com">HTTP/3 support in .NET 6</a><br>Sam Spencer</p><p>Along with all the other announcements last week, <a href="https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/?ref=daveabrock.com">Sam Spencer writes about HTTP/3 support in .NET 6</a>. As a refresher, Sam explains why HTTP/3 is important: "We have all gone mobile and much of the access is now from phones and tablets using Wi-Fi and cellular connections which can be unreliable. Although HTTP/2 enables multiple streams, they all go over a connection which is TLS encrypted, so if a TCP packet is lost all of the streams are blocked until the data can be recovered. This is known as the head of line blocking problem."</p><p>"HTTP/3 solves these problems by using a new underlying connection protocol called QUIC. QUIC uses UDP and has TLS built in, so it’s faster to establish connections as the TLS handshake occurs as part of the connection. Each frame of data is independently encrypted so it no longer has the head of line blocking in the case of packet loss."</p><p>The RFC for HTTP/3 is not yet finalized and subject to change, but you can start to play around with HTTP/3 and .NET 6 <a href="https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/?ref=daveabrock.com#http-3-support-in-net-6">if you're up for getting your hands dirty</a>. You can use the <code>HttpClient</code> as well <a href="https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/?ref=daveabrock.com#http-3-support-in-net-6">if you enable a runtime flag</a>. <a href="https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6?ref=daveabrock.com">Check out the post</a> for details.</p><p>More from last week:</p><ul><li>Some releases: WinUI 2.7 <a href="https://docs.microsoft.com/en-us/windows/apps/winui/winui2/release-notes/winui-2.7?ref=daveabrock.com" rel="nofollow">is out</a>, Dapr v1.4 <a href="https://blog.dapr.io/posts/2021/09/16/dapr-v1.4-is-now-available/?ref=daveabrock.com" rel="nofollow">is now out</a>, and so is <a href="https://platform.uno/blog/uno-platform-3-10-day-0-support-for-net-6-rc1-winui-infobadge-windows-11-fluent-styles/?ref=daveabrock.com" rel="nofollow">Uno Platform 3.10</a>. Also, <a href="https://corewcf.github.io/blog/2021/09/13/corewcf-0_3_0_release?ref=daveabrock.com">CoreWCF has a new release</a>.</li><li>Leslie Richardson <a href="https://devblogs.microsoft.com/visualstudio/the-future-of-visual-studio-extensibility-is-here?ref=daveabrock.com" rel="nofollow">writes about the future of Visual Studio extensibility</a>.</li><li>Vasu Jakkal <a href="https://www.microsoft.com/security/blog/2021/09/15/the-passwordless-future-is-here-for-your-microsoft-account/?ref=daveabrock.com" rel="nofollow">writes about passwordless personal Microsoft accounts</a>.</li><li>The NuGet folks <a href="https://devblogs.microsoft.com/nuget/introducing-package-source-mapping/?ref=daveabrock.com">introduce package source mapping</a>.</li></ul><h2 id="%F0%9F%93%85-community-and-events">📅 Community and events</h2><p><a href="https://dotnetfoundation.org/blog/2021/09/01/announcing-net-foundation-elections-2021?ref=daveabrock.com">Announcing the Candidates .NET Foundation Election 2021</a><br>Nicole Miller</p><p>This post isn't new but if you're a member of the .NET Foundation, they are <a href="https://dotnetfoundation.org/blog/2021/09/01/announcing-net-foundation-elections-2021?ref=daveabrock.com">looking to fill a couple of seats on the Board of Directors</a>. Browse the blog post to learn more about the candidates (Nicole has interviewed each candidate, as well). Voting ends by the end of today (September 20) at 11:59 PST in the USA. (Disclaimer: I was <a href="https://dotnetfoundation.org/about/election/?ref=daveabrock.com">on the Election Board</a> and would love to hear feedback about the process if you have it. We aren't perfect but are trying!)</p><p>More from last week:</p><ul><li>The Netflix Tech Blog <a href="https://netflixtechblog.com/practical-api-design-at-netflix-part-2-protobuf-fieldmask-for-mutation-operations-2e75e1d230e4?ref=daveabrock.com" rel="nofollow">continues their practical API design series</a>, and also <a href="https://netflixtechblog.com/the-show-must-go-on-securing-netflix-studios-at-scale-19b801c86479?ref=daveabrock.com" rel="nofollow">writes about securing at scale</a>.</li><li>For community standups: ASP.NET <a href="https://www.youtube.com/watch?v=cpt0Ljs35YA&ref=daveabrock.com">talks about Blazor .NET 6 RC1 updates</a>, Machine Learning <a href="https://www.youtube.com/watch?v=s3Epe3ox72s&ref=daveabrock.com">walks through TorchSharp</a>, and .NET Tooling <a href="https://www.youtube.com/watch?v=4kwvcufEAk4&ref=daveabrock.com">discusses updates for Visual Studio for Mac</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=kuJc6HsRbJk&ref=daveabrock.com">hosts a .NET IoT AMA</a>.</li></ul><h2 id="%F0%9F%8C%8E-web-development">🌎 Web development</h2><p><a href="https://www.tpeczek.com/2021/09/websocket-per-message-compression-in.html?ref=daveabrock.com">WebSocket per-message compression in ASP.NET Core 6</a><br>Tomasz Pęczek</p><p>New with ASP.NET Core 6, you can compress WebSocket messages. Tomasz Pęczek has been working with it so far <a href="https://www.tpeczek.com/2021/09/websocket-per-message-compression-in.html?ref=daveabrock.com">and has a nice post</a> with a GitHub repository you can reference. It ships with a <code>WebSocketAcceptContext</code> object, which includes a <code>DangerousEnableCompression</code> property. Why?</p><p>"You might be wondering why such a "scary" property name. It's not because things may fail. If the client doesn't support compressions (or doesn't support compression with specific parameters), the negotiated connection will have compression disabled. It's about security. Similarly to HTTPS, encrypted WebSocket connections are subject to <em><em>CRIME/BREACH</em></em> attacks. If you are using encryption, you should be very cautious and not compress sensitive messages."</p><p>Also from last week:</p><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/minimal-apis-at-a-glance-in-net-6?ref=daveabrock.com" rel="nofollow">writes more about Minimal APIs in .NET 6</a>.</li><li>Visual Studio Magazine <a href="https://visualstudiomagazine.com/articles/2021/09/14/backend-web.aspx?ref=daveabrock.com" rel="nofollow">confirms that PHP runs the world</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/async-processing-of-long-running-tasks-in-asp-net-core/?ref=daveabrock.com" rel="nofollow">writes about async processing of long-running tasks in ASP.NET Core</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/using-dotnet-to-validate-json-with-json-schema?ref=daveabrock.com" rel="nofollow">uses .NET to validate JSON with JSON Schema</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/blazor-updates-dotnet-6-visual-studio-2022?ref=daveabrock.com" rel="nofollow">works on .NET 6 Blazor updates in Visual Studio 2022</a>.</li><li>Matthew MacDonald asks: <a href="https://medium.com/young-coder/is-blazor-the-future-or-just-another-walled-garden-441842cc249d?ref=daveabrock.com" rel="nofollow">is Blazor the future or just another walled garden?</a></li></ul><h2 id="%F0%9F%94%A7-tools">🔧 Tools</h2><p><a href="https://blog.jetbrains.com/dotnet/2021/09/13/advanced-git-workflow-tips/?ref=daveabrock.com">Advanced Git Workflow Tips</a><br>Khalid Abuhakmeh</p><p>Over at the JetBrains blog, Khalid Abuhakmeh writes about ways to make working with Git easier, armed with some JetBrains Rider tips as well. I learned about cleaning your repository of non-tracked artifacts by using <code>git clean -xdf</code>. An irreversible command, you can use it to prevent folder bloat that occurs in new repos when you're working with non-tracked files like dependencies and build items.</p><ul><li>Chinedu Imoh <a href="https://www.telerik.com/blogs/introduction-github-codespaces?ref=daveabrock.com" rel="nofollow">introduces GitHub Codespaces</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/09/13/advanced-git-workflow-tips/?ref=daveabrock.com" rel="nofollow">offers advanced Git workflow tips</a>.</li><li>Ryan Staatz <a href="https://thenewstack.io/5-things-developers-need-to-know-about-kubernetes-management/?ref=daveabrock.com" rel="nofollow">writes about 5 things developers need to know about Kubernetes management</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/auto-creating-fields-vs?ref=daveabrock.com" rel="nofollow">customizes fields generation in Visual Studio 2019</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/debugging-a-net-app-on-linux-from-windows-visual-studio-with-wsl/?ref=daveabrock.com" rel="nofollow">debugs a .NET App on Linux from Windows Visual Studio with WSL</a>.</li></ul><h2 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Anwar Al Jahwari <a href="https://better-dev.io/strategy-pattern/?ref=daveabrock.com" rel="nofollow">works on the Strategy pattern</a>.</li><li>Steve Fenton <a href="https://www.stevefenton.co.uk/2021/09/a-perspective-on-laws-of-software-development/?ref=daveabrock.com" rel="nofollow">offers a perspective on the laws of software development</a>.</li><li>Steve Smith asks: <a href="https://ardalis.com/should-controllers-reference-repositories-services/?ref=daveabrock.com" rel="nofollow">should controllers reference repositories or services?</a></li><li>Mahesh Chand <a href="https://www.c-sharpcorner.com/article/top-10-tips-to-increase-productivity/?ref=daveabrock.com" rel="nofollow">offers some productivity tips</a>.</li></ul><h2 id="%E2%9B%85-the-cloud">⛅ The cloud</h2><ul><li>Brian Weeteling <a href="https://www.getadigital.com/blog/semantic-search-with-azure-cognitive-search?ref=daveabrock.com" rel="nofollow">writes about semantic search with Azure Cognitive Search</a>.</li><li>The CNCF asks: <a href="https://www.cncf.io/blog/2021/09/15/is-serverless-the-right-way-to-cloud/?ref=daveabrock.com" rel="nofollow">is serverless the right way to the cloud</a>?</li><li>Justin Yoo <a href="https://dev.to/azure/ms-graph-blazor-webassembly-and-azure-static-web-apps-3p1d?ref=daveabrock.com" rel="nofollow">works on MS Graph, Blazor WebAssembly, and Azure Static Web Apps</a>.</li></ul><h2 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h2><ul><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/?ref=daveabrock.com" rel="nofollow">looks inside the ConfigurationManager in .NET 6</a>.</li><li>The Code Maze blog <a href="https://code-maze.com/introduction-system-text-json-examples/?ref=daveabrock.com" rel="nofollow">introduces System.Text.Json</a>.</li></ul><h2 id="%F0%9F%93%94-languages">📔 Languages</h2><ul><li>Something I missed a while back: Sam Walpole <a href="https://samwalpole.com/a-brief-introduction-to-f-for-object-oriented-developers?ref=daveabrock.com">introduces F# for OO developers</a>.</li><li>Maarten Hus writes about <a href="https://www.maartenhus.nl/blog/pipeline-operator-hack-vs-fsharp/?ref=daveabrock.com">pipeline operator possibilities in F#</a>.</li></ul><h2 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h2><ul><li>Luis Matos <a href="https://luismts.com/password-validation-rules-xamarin-forms/?ref=daveabrock.com" rel="nofollow">works on password validation rules with Xamarin Forms</a>.</li><li>Almir Vuk <a href="https://www.infoq.com/news/2021/09/community-toolkit-maui-compat/?ref=daveabrock.com" rel="nofollow">writes about the .NET MAUI compatibility packages for the Xamarin Community Toolkit</a>.</li></ul><h2 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and Videos</h2><ul><li>Coding Blocks <a href="https://www.codingblocks.net/podcast/docker-licensing-career-coding/?ref=daveabrock.com" rel="nofollow">discusses Docker licensing, career, and coding questions</a>.</li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1757&ref=daveabrock.com" rel="nofollow">talks about going from software developer to software engineer</a>, and The Overflow <a href="https://stackoverflow.blog/2021/09/17/podcast-376-writing-the-roadmap-from-engineer-to-manager/?ref=daveabrock.com" rel="nofollow">talks about the roadmap from engineer to manager</a>.</li><li>Merge Conflict <a href="https://www.mergeconflict.fm/271?ref=daveabrock.com" rel="nofollow">discusses how not to monetize an app</a>.</li><li>Adventures in .NET ask: <a href="https://devchat.tv/adventures-in-dotnet/how-do-you-grow-net-086/?ref=daveabrock.com" rel="nofollow">how do you grow?</a></li><li>The .NET MAUI Podcast <a href="https://www.dotnetmauipodcast.com/98?ref=daveabrock.com" rel="nofollow">provides an update</a>.</li><li>The Working Code Podcast asks: <a href="https://www.bennadel.com/blog/4114-working-code-podcast-episode-040-are-database-transactions-overrated.htm?ref=daveabrock.com" rel="nofollow">are database transactions overrated?</a></li><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-211-git-for-programmers-with-jesse-liberty/?ref=daveabrock.com" rel="nofollow">talks to Jesse Liberty about Git</a>.</li><li>The Unhandled Exception Podcast <a href="https://unhandledexceptionpodcast.com/posts/0023-git/?ref=daveabrock.com" rel="nofollow">talks about Git with Jesse Liberty and James World</a>.</li><li>The Changelog <a href="https://changelog.com/podcast/459?ref=daveabrock.com" rel="nofollow">discusses GitHub Codespaces</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/daniel-roth-on-web-development-with-net-6-episode-158?ref=daveabrock.com" rel="nofollow">talks to Daniel Roth about web dev on .NET 6</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=9c_qdEA_I6k&ref=daveabrock.com" rel="nofollow">walk through DateOnly and TimeOnly in .NET 6</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Accepting-online-payments-with-Stripe?ref=daveabrock.com" rel="nofollow">discusses accepting online payments with Stripe</a> and <a href="https://www.youtube.com/watch?v=PYHZLCTC7i0&ref=daveabrock.com">performance and load testing with k6</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #62: 👋 And we&#x27;re back ]]></title>
        <description><![CDATA[ This week, we are back! ]]></description>
        <link>https://www.daveabrock.com/2021/09/19/dotnet-stacks-62/</link>
        <guid isPermaLink="false">613ca82115458e004b3a6040</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 18 Sep 2021 19:05:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/09/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This is the web version of my weekly newsletter, The .NET Stacks, originally sent to email subscribers on September 13, 2021. Subscribe at the bottom of the post to get this right away!</em></p><p>Happy Monday! Miss me? A few of you said you have, but I'm 60% sure that's sarcasm.</p><p>As you know, I took the last month or so off from the newsletter to focus on other things. I know I wasn't exactly specific on why, and appreciate some of you reaching out. I wasn't comfortable sharing it at the time, but I needed to take time away to focus on determining the next step in my career. If you've interviewed lately, I'm sure you understand ... it really is a full-time job.  I'm happy to say I've accepted a remote tech lead role for a SaaS company here. </p><p>I'm rested and ready, so let's get into it! I'm trying something a little different this week—feel free to let me know what you think.</p><hr><h2 id="%F0%9F%94%A5-my-favorite-from-last-week">🔥 My favorite from last week</h2><p><a href="https://benfoster.io/blog/minimal-apis-why-should-you-care/?ref=daveabrock.com"><strong>ASP.NET 6.0 Minimal APIs, why should you care?</strong></a><br><strong>Ben Foster</strong></p><p>We've talked about Minimal APIs a lot in this newsletter and it's <a href="https://twitter.com/hashtag/minimalapis?ref=daveabrock.com">quite the hot topic</a> in the .NET community. An alternative way to write APIs in .NET 6 and beyond, there's a lot of folks wondering if it's suitable for production, or can lead to misuse. </p><p>Ben notes: "Minimal simply means that it contains the minimum set of components needed to build HTTP APIs ... It doesn’t mean that the application you build will be simple or not require good design."</p><p>"I find that one of the biggest advantages to Minimal APIs is that they make it easier to build APIs in an <em>opinionated</em> way. After many years building HTTP services, I have a preferred approach. With MVC I would replace the built-in validation with Fluent Validation and my controllers were little more than a dispatch call to Mediatr. With Minimal APIs I get even more control. Of course if MVC offers everything you need, then use that."</p><p>In a similar vein, Nick Chapsas has <a href="https://www.youtube.com/watch?v=4ORO-KOufeU&ref=daveabrock.com">a great walkthrough</a> on strategies for building production-ready Minimal APIs. No one expects your API to be in one file, and he shows practical ways to deal with dependencies while leveraging minimal API patterns. Damian Edwards <a href="https://twitter.com/DamianEdwards/status/1436740934297784322?ref=daveabrock.com">has a nice Twitter thread, as well</a>. As great as these community discussions are, I really think the greatest benefit is getting lost: the performance gains.</p><hr><h2 id="%F0%9F%93%85-community-and-events">📅 Community and events</h2><p><strong><a href="https://github.blog/2021-09-07-increasing-developer-happiness-github-code-scanning/?ref=daveabrock.com">Increasing developer happiness with GitHub code scanning</a><br>Sam Partington</strong></p><p>If you work in GitHub, you probably already know that GitHub utilizes code scanning to <a href="https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning?ref=daveabrock.com">find security vulnerabilities and errors in your repository</a>. Sam Partington writes about something you might not know: they use CodeQL—their internal code analysis engine—to protect themselves from common coding mistakes. </p><p>Here's what Sam says about loopy performance issues: "In addition to protecting against missing error checking, we also want to keep our database-querying code performant. N+1 queries are a common performance issue. This is where some expensive operation is performed once for every member of a set, so the code will get slower as the number of items increases. Database calls in a loop are often the culprit here; typically, you’ll get better performance from a batch query outside of the loop instead."</p><p>"We created a <a href="https://github.com/github/codeql-go/blob/main/ql/src/experimental/CWE-400/DatabaseCallInLoop.ql?ref=daveabrock.com" rel="noopener">custom CodeQL query</a> ... We filter that list of calls down to those that happen within a loop and fail CI if any are encountered. What’s nice about CodeQL is that we’re not limited to database calls directly within the body of a loop―calls within functions called directly or indirectly from the loop are caught too."</p><p>You can check out the post for more details and learn how to use these queries or make your own.</p><p>More from last week:</p><ul><li>Simon Bisson <a href="https://www.infoworld.com/article/3631383/use-the-visual-studio-code-editor-in-your-own-projects.html?ref=daveabrock.com" rel="nofollow">writes about how to use the VS Code editor in your own projects</a>.</li><li>The Netflix Tech Blog <a href="https://netflixtechblog.com/practical-api-design-at-netflix-part-1-using-protobuf-fieldmask-35cfdc606518?ref=daveabrock.com" rel="nofollow">starts a series on practical API design</a> and also <a href="https://netflixtechblog.com/decision-making-at-netflix-33065fa06481?ref=daveabrock.com" rel="nofollow">starts writing about their decision-making process</a>.</li><li>The .NET Docs Show talks about <a href="https://www.youtube.com/watch?v=8Ac2QMdusrs&ref=daveabrock.com">micr0 frontends with Blazor</a>.</li><li>For community standups, Entity Framework <a href="https://www.youtube.com/watch?v=lLz5WwZKRW4&ref=daveabrock.com">talks about OSS projects</a>, ASP.NET <a href="https://www.youtube.com/watch?v=0wscoCzfIH0&ref=daveabrock.com">has an anniversary</a>, .NET MAUI <a href="https://www.youtube.com/watch?v=sm6N4HQ_5iA&ref=daveabrock.com">discusses accessibility</a>, and Machine Learning <a href="https://www.youtube.com/watch?v=youpU2MkPPI&ref=daveabrock.com">holds office hours</a>.</li></ul><hr><h2 id="%F0%9F%8C%8E-web-development">🌎 Web development</h2><p><strong><a href="https://khalidabuhakmeh.com/how-to-map-a-route-in-an-aspnet-core-mvc-application?ref=daveabrock.com">How To Map A Route in an ASP.NET Core MVC application</a><strong><br></strong>Khalid Abuhakmeh</strong></p><p>If you're new to ASP.NET Core web development, Khalid put together a nice post on how to add an existing endpoint to an existing ASP.NET Core MVC app. Even if you aren't a beginner, you might learn how to resolve sticky routing issues. At the bottom of the post, he has a nice checklist you should consider when adding a new endpoint.</p><p>More from last week:</p><ul><li>Ben Foster <a href="https://benfoster.io/blog/minimal-apis-custom-model-binding-aspnet-6/?ref=daveabrock.com" rel="nofollow">explores custom model binding with Minimal APIs in .NET 6</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/debugging-system-formatexception-when-launching-asp-net-core/?ref=daveabrock.com" rel="nofollow">debugs System.FormatException when launching ASP.NET Core</a>.</li><li>Jeremy Morgan <a href="https://www.codeproject.com/Articles/5312004/Building-a-Micro-Web-API-with-Azure-Functions-and?ref=daveabrock.com" rel="nofollow">builds a small web API with Azure Functions and SQLite</a>.</li><li>Ed Charbeneau <a href="https://www.telerik.com/blogs/low-code-data-grids-blazor?ref=daveabrock.com" rel="nofollow">works with low-code data grids and Blazor</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/a-net-6-minimal-api-todo-example-playground?ref=daveabrock.com" rel="nofollow">works with a Minimal API todo app</a>.</li></ul><hr><h2 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h2><p><strong><a href="https://andrewlock.net/using-source-generators-with-blazor-in-dotnet-6/?ref=daveabrock.com">Using Source Generators with Blazor components in .NET 6</a><strong><br></strong>Andrew Lock</strong></p><p>When Andrew was upgrading a Blazor app to .NET 6, he found that source generators that worked in .NET 5 failed to discover Blazor components in his .NET 6 app because of changes to the Razor compilation process.</p><p>He writes: "The problem is that my source generators were relying on the <em><em>output</em></em> of the Razor compiler in .NET 5 ... My source generator was looking for components in the compilation that are decorated with <code>[RouteAttribute]</code>. With .NET 6, the Razor tooling is a source generator, so there <em><em>is</em></em> no 'first step'; the Razor tooling executes at the <em><em>same time as my source generator</em></em>. That is great for performance, but it means the files my source generator was relying on (the generated component classes) <em><em>don't exist</em></em> when my generator runs."</p><p>While this is by design, Andrew has a great post underlying the issue and potential workarounds.</p><p>More from last week:</p><ul><li>Mark Downie <a href="https://www.poppastring.com/blog/favorite-improvements-in-net-6?ref=daveabrock.com" rel="nofollow">writes about his favorite improvements in .NET 6</a>.</li><li>Sergey Vasiliev <a href="https://dzone.com/articles/optimization-of-net-applications-a-big-result-of-s?ref=daveabrock.com" rel="nofollow">writes about optimizing .NET apps</a>.</li><li>Paweł Szydziak <a href="https://developer.okta.com/blog/2021/09/08/sonar-qube-dotnet?ref=daveabrock.com" rel="nofollow">writes cleaner, safer code with SonarQube, Docker, and .NET Core</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/how-to-desktop-2022?ref=daveabrock.com" rel="nofollow">writes about how to develop for desktop in 2022</a>, and also <a href="https://www.telerik.com/blogs/apples-maui?ref=daveabrock.com" rel="nofollow">about developing for .NET MAUI on macOS</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/09/05/manually-parsing-a-json-string-using-system-text-json/?ref=daveabrock.com" rel="nofollow">manually parses a JSON string using System.Text.Json</a>.</li><li>Johnson Towoju <a href="https://code-maze.com/writing-logs-to-sql-server-using-nlog/?ref=daveabrock.com" rel="nofollow">writes logs to SQL Server using NLog</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/using-source-generators-with-blazor-in-dotnet-6/?ref=daveabrock.com" rel="nofollow">uses source generators with Blazor components in .NET 6</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Sep/03/Launching-VS-Code-cleanly-from-a-NET-Application?ref=daveabrock.com" rel="nofollow">launches Visual Studio Code cleanly from a .NET app</a>.</li><li>Jiří Činčura <a href="https://www.tabsoverspaces.com/233870-csharp-static-constructor-called-multiple-times?ref=daveabrock.com" rel="nofollow">calls a C# static constructor multiple times</a>.</li></ul><hr><h2 id="%E2%9B%85-the-cloud">⛅ The cloud</h2><p><strong><a href="https://adamstorr.azurewebsites.net/blog/minimal-api-in-net6.0-out-of-process-azure-functions?ref=daveabrock.com">Minimal Api in .NET 6 Out Of Process Azure Functions</a><strong><strong><strong><br></strong></strong></strong>Adam Storr</strong></p><p>With all this talk about Minimal APIs, Adam asks: can I use it with the new out-of-process Azure Functions model in .NET 6?</p><p>He says: "Azure Functions with HttpTriggers are similar to ASP.NET Core controller actions in that they handle http requests, have routing, can handle model binding, dependency injection etc. so how could a 'Minimal API' using Azure Functions look?"</p><p>More from last week:</p><ul><li>Damien Bowden <a href="https://damienbod.com/2021/09/06/using-azure-security-groups-in-asp-net-core-with-an-azure-b2c-identity-provider/?ref=daveabrock.com" rel="nofollow">uses Azure security groups in ASP.NET Core with an Azure B2C identity provider</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/09/azure-identity-301/?ref=daveabrock.com" rel="nofollow">works with the ChainedTokenCredential in the Azure Identity library</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/minimal-api-in-net6.0-out-of-process-azure-functions?ref=daveabrock.com" rel="nofollow">uses .NET 6 Minimal APIs with out-of-process Azure Functions</a>.</li></ul><hr><h2 id="%F0%9F%94%A7-tools">🔧 Tools</h2><p><strong><a href="https://devblogs.microsoft.com/visualstudio/new-improved-attach-to-process-dialog-experience/?ref=daveabrock.com">New Improved Attach to Process Dialog Experience</a><br>Harshada Hole</strong></p><p>With the 2022 update, Visual Studio is improving the debugging experience—included is a new Attach to Process dialog experience.</p><p>Harshada says: "We have added command-line details, app pool details, parent/child process tree view, and the select running window from the desktop option in the attach to process dialog. These make it convenient to find the right process you need to attach. Also, the Attach to Process dialog is now asynchronous, making it interactive even when the process list is updating." The post walks through these updates in detail.</p><p>More from last week:</p><ul><li>Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/taking-the-ef-core-azure-cosmos-db-provider-for-a-test-drive?ref=daveabrock.com" rel="nofollow">looks at the EF Core Azure Cosmos DB provider</a>.</li><li>Harshada Hole <a href="https://devblogs.microsoft.com/visualstudio/new-improved-attach-to-process-dialog-experience?ref=daveabrock.com" rel="nofollow">writes about the new Attach to Process dialog experience in Visual Studio</a>.</li><li>Ben De St Paer-Gotch <a href="https://www.docker.com/blog/the-magic-behind-the-scenes-of-docker-desktop/?ref=daveabrock.com" rel="nofollow">goes behind the scenes on Docker Desktop</a>.</li><li>Esteban Solano Granados <a href="https://stvansolano.github.io/2021/08/02/Playing-with-NET-6-preview-csharp10-docker-containers/?ref=daveabrock.com">plays with .NET 6, C# 10, and Docker</a>.</li></ul><hr><h2 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><p><strong><a href="https://martinfowler.com/articles/ship-show-ask.html?ref=daveabrock.com"><a href="https://devblogs.microsoft.com/visualstudio/new-improved-attach-to-process-dialog-experience/?ref=daveabrock.com">S</a>hip / Show / Ask: A modern branching strategy</a><br>Rouan Wilsenach</strong></p><p>Rouan says: "Ship/Show/Ask is a branching strategy that combines the features of Pull Requests with the ability to keep shipping changes. Changes are categorized as either Ship (merge into mainline without review), Show (open a pull request for review, but merge into mainline immediately), or Ask (open a pull request for discussion before merging)."</p><p>More from last week:</p><ul><li>Liana Martirosyan <a href="https://www.infoq.com/articles/team-performance-learning/?ref=daveabrock.com" rel="nofollow">writes about enabling team learning and boost performance</a>.</li><li>Sagar Nangare <a href="https://thenewstack.io/measuring-user-experience-in-modern-applications-and-infrastructure/?ref=daveabrock.com" rel="nofollow">writes about measuring user experience in modern applications and infrastructure</a>.</li><li>Neal Ford and Mark Richards <a href="https://www.infoq.com/podcasts/software-architecture-hard-parts/?ref=daveabrock.com" rel="nofollow">talk about the hard parts of software architecture</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/event-sourced-aggregate-design-focus-on-business-logic/?ref=daveabrock.com" rel="nofollow">discusses event-sourced aggregate design</a>.</li><li>Steve Smith <a href="https://ardalis.com/refactoring-value-objects/?ref=daveabrock.com" rel="nofollow">refactors to value objects</a>.</li><li>Sam Milbrath <a href="https://blog.trello.com/hold-team-accountable-without-micromanaging?ref=daveabrock.com" rel="nofollow">writes about holding teams accountable without micromanaging</a>.</li><li>Helen Scott asks: <a href="https://helenjoscott.medium.com/how-can-you-stay-ahead-of-the-curve-as-a-developer-a27d728980a2?ref=daveabrock.com" rel="nofollow">how can you stay ahead of the curve as a developer?</a></li><li>Rouan Wilsenach <a href="https://martinfowler.com/articles/ship-show-ask.html?ref=daveabrock.com" rel="nofollow">writes about a ship / show / ask branching strategy</a>.</li><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/09/07/integration-testing-ihost-lifecycle-with-xunit-net/?ref=daveabrock.com" rel="nofollow">writes about integration Testing using the IHost Lifecycle with xUnit.Net</a>.</li></ul><hr><h2 id="%F0%9F%8E%A4-podcasts-and-videos">🎤 Podcasts and Videos</h2><ul><li>Serverless Chats <a href="https://www.serverlesschats.com/109/?ref=daveabrock.com" rel="nofollow">discusses serverless for beginners</a>.</li><li>The .NET Core Show <a href="https://dotnetcore.show/episode-82-dotpurple-with-michael-babienco/?ref=daveabrock.com" rel="nofollow">talks about DotPurple With Michael Babienco</a>.</li><li>The Changelog <a href="https://changelog.com/podcast/458?ref=daveabrock.com" rel="nofollow">talks to a lawyer about GitHub Copilot</a>.</li><li>Technology and Friends <a href="https://www.davidgiard.com/2021/09/06/SamBasuOnNETMAUI.aspx?ref=daveabrock.com" rel="nofollow">talks to Sam Basu about .NET MAUI</a>.</li><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Web-Live-Preview?ref=daveabrock.com" rel="nofollow">talks about Web Live Preview</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=QI4nYR_vAXU&ref=daveabrock.com" rel="nofollow">talk about new Git commands</a>.</li><li>Adventures in .NET <a href="https://devchat.tv/adventures-in-dotnet/get-interactive-with-jupyter-notebook-net-085/?ref=daveabrock.com" rel="nofollow">talk about Jupyter notebooks</a>.</li><li>The On .NET Show <a href="https://www.youtube.com/watch?v=S4tsbjMx2_o&ref=daveabrock.com">migrates apps to modern authentication</a> and <a href="https://www.youtube.com/watch?v=Wl4ybEE4Bxc&ref=daveabrock.com">processes payments with C# and Stripe</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Exploring Fiddler Jam: Get Your Time Back by Solving Issues Faster ]]></title>
        <description><![CDATA[ Let&#39;s learn more about Fiddler Jam, an end-to-end troubleshooting solution that helps users, support, and engineering
solve problems quickly. ]]></description>
        <link>https://www.daveabrock.com/2021/08/25/exploring-fiddler-jam/</link>
        <guid isPermaLink="false">611945c2dab7b3003b9e98a8</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 25 Aug 2021 08:38:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1468577760773-139c2f1c335f?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDN8fGphbXxlbnwwfHx8fDE2MjkwNDY2MDM&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This article was originally posted on the <a href="https://www.telerik.com/blogs/exploring-fiddler-jam-get-time-back-solving-issues-faster?ref=daveabrock.com">Telerik Developer Blog</a>.</em></p><p>Your most important resource is time. When non-technical users encounter issues and need your help, how much of this important resource are you spending?</p><p>We've all been there: a user reports an issue that often doesn't have the context and details you would like—for example, "the site is slow"—and your support and engineering teams eat up a lot of their time on the back and forth. You might ask the user to send along screenshots of the issue. You might have to get on a call to reproduce the issue—and risk an "it worked differently before" situation. In addition, passing around insecure data can lead to security and compliance issues with your organization.</p><p>This painful process provides headaches for everyone. End users don't have an easy way to submit logs securely, support staff wastes a lot of back-and-forth time to reproduce the issue, and engineering teams have trouble understanding the context of the issue and reproducing it successfully.</p><p>Have you heard about Fiddler Jam? A <a href="https://www.telerik.com/blogs/introducing-fiddler-jam?ref=daveabrock.com">relative newcomer</a> to the Telerik Fiddler suite of products, Jam is a solution to help support and development teams troubleshoot remote issues with web applications in a quick, easy and secure fashion. How does it work? Users of your site can use a Chrome extension to share the full context of the issue—capturing network logs, browser console logs and screenshots—and the support team can analyze the data immediately. If needed, developers can reproduce and debug the issue using the <a href="https://www.telerik.com/fiddler/fiddler-everywhere?ref=daveabrock.com">Fiddler Everywhere debugging proxy</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-3.png" class="kg-image" alt loading="lazy" width="1482" height="890" srcset="https://www.daveabrock.com/content/images/size/w600/2021/08/image-3.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/08/image-3.png 1000w, https://www.daveabrock.com/content/images/2021/08/image-3.png 1482w" sizes="(min-width: 720px) 720px"></figure><p>When I first learned about Fiddler Jam, I had a question that you might be asking yourself, too: in such a busy market, why should I use Fiddler Jam when I have free tools like a browser's developer tools? In this post, I'll make the case for Fiddler Jam in three different ways.</p><h2 id="users-can-easily-send-issue-information">Users Can Easily Send Issue Information</h2><p>When getting issue details from a user, you'll lack appropriate context—whether users call you, open a support ticket or email screenshots. You're now left with putting together a puzzle from what you're told and what your telemetry tells you. While it's relatively easy to know when an API service is down, what about a stubborn click event that isn't logged?</p><p>With Fiddler Jam, it's easy to allow non-technical users to provide context around the issue. In many cases, users can become frustrated to spend so much time reproducing an issue for you when they are already frustrated that things aren't working. With a couple of button clicks, users can provide the complete context of their interaction with your web app.</p><p>After <a href="https://docs.telerik.com/fiddler-jam/extension/installation?ref=daveabrock.com">asking users to download</a> the Fiddler Jam <a href="https://chrome.google.com/webstore/detail/fiddler-jam/fnkjlegmkbicdodlheligomlfbdblpfj?ref=daveabrock.com">Chrome extension</a>—which you can use with Google Chrome and Microsoft Edge—users will see a Fiddler Jam icon next to the browser's address bar. Users can then click the icon to start capturing the issue.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image.png" class="kg-image" alt loading="lazy" width="558" height="609"></figure><h2 id="robust-security-practices-are-built-in">Robust Security Practices are Built-In</h2><p>By default, Fiddler Jam also handles the work of sending data securely. If you review the Advanced Options in the Chrome extension, you'll see a few options you can configure based on your security needs. All options are enabled by default.</p><ul><li><strong>Take screenshots while capturing</strong> - This option adds a screenshot from the active Chrome tab. If the screen shows sensitive data, consider disabling it.</li><li><strong>Capture console</strong> - This option records any developer console outputs. Again, consider disabling this if your logs have sensitive information.</li><li><strong>Mask cookies</strong> - This option masks cookie values so that they aren't visible in the logs. The cookie names will still be visible.</li><li><strong>Mask post data</strong> - This option masks data sent along in a POST request, like form information.</li><li><strong>Disable cache</strong> - This option asks the browser to skip network requests cache and downloads fresh content from the server</li></ul><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-1.png" class="kg-image" alt loading="lazy" width="553" height="558"></figure><p>After users capture a session, they can share the session using a public link or Password Protection. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-2.png" class="kg-image" alt loading="lazy" width="551" height="613"></figure><p>The password-protected logs are secured with AES-CTR encryption, and all logs are stored in the cloud. The Fiddler Jam team won't have access to (and can't recover) password-protected log content. See the <a href="https://docs.telerik.com/fiddler-jam/security?ref=daveabrock.com">Fiddler Jam documentation</a> for details.</p><h2 id="use-powerful-tooling-to-review-the-entire-context-quickly">Use Powerful Tooling to Review the Entire Context Quickly</h2><p>With Fiddler Jam, you can use various tooling options to make the most of the data. When a user shares a link, you'll be sent to the Telerik Fiddler Jam dashboard for a detailed view of the logs and information on the request—like headers and request/response bodies. Here's how it looks when I'm looking at a server error, where I have <em>Something bad happened</em> as a response. (I suppose it <em>is</em> an accurate statement but could use more investigation.)</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-4.png" class="kg-image" alt loading="lazy" width="1492" height="1353" srcset="https://www.daveabrock.com/content/images/size/w600/2021/08/image-4.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/08/image-4.png 1000w, https://www.daveabrock.com/content/images/2021/08/image-4.png 1492w" sizes="(min-width: 720px) 720px"></figure><p>By default, I can also look at user actions. I can look at the button press that initiated the call to the server.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-5.png" class="kg-image" alt loading="lazy" width="1478" height="1348" srcset="https://www.daveabrock.com/content/images/size/w600/2021/08/image-5.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/08/image-5.png 1000w, https://www.daveabrock.com/content/images/2021/08/image-5.png 1478w" sizes="(min-width: 720px) 720px"></figure><p>In future versions, Fiddler Jam will take screenshots of more user actions like inputs and scroll events. These actions are stored in the cloud at no additional cost to you. It's one of my favorite features. There's no guessing of what a user said they did and what really happened. It's all here.</p><p>The data comes in the format of an HTTP Archive (HAR) file, which is an industry-standard JSON-formatted file that saves HTTP performance data. You can download the HAR file for further inspection and even load the HAR file for mocking. To be clear, this is not the mocking my team does to me when I introduce a bug to the codebase. Instead, Jam sends the data to the Chrome extension, where you can load a session in the browser. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/08/image-6.png" class="kg-image" alt loading="lazy" width="556" height="429"></figure><p>Finally, the engineering team can open the session in Fiddler Everywhere for further investigation. With Fiddler Everywhere's powerful capabilities, you can even replay requests from a user's session!</p><h2 id="summary">Summary</h2><p>In this post, I've shown you how Fiddler Jam provides robust capabilities to help you reproduce and resolve issues quickly. More than just another set of developer tools, it's a full end-to-end troubleshooting solution designed to work well for users, support, and engineering alike. Get started with Fiddler Jam today by going to the Fiddler Jam site and <a href="https://www.telerik.com/fiddler-jam?ref=daveabrock.com">signing up for a free 14-day trial</a>. </p><p></p><p></p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #61: 🚌 Let&#x27;s go on a community blog tour ]]></title>
        <description><![CDATA[ In the latest issue, let&#39;s go on a community blog tour. ]]></description>
        <link>https://www.daveabrock.com/2021/08/15/dotnet-stacks-61/</link>
        <guid isPermaLink="false">61106fdadb671e003e96a283</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 15 Aug 2021 11:48:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/08/THE-.NET-STACKS-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Would you look at that — it's Monday again. I hope you had a wonderful weekend. Here's what we have going on this week. </p><ul><li>Let's go on a community blog tour</li><li>Did you know?</li><li>A housekeeping note</li><li>Last week in the .NET world</li></ul><hr><h2 id="lets-go-on-a-community-blog-tour">Let's go on a community blog tour</h2><p>Every week, I provide a big list of quick links for you to check out. I have them this week as I always do, but I wanted to also talk about five or so community blog posts this week. (To be clear, there are always many more great posts from the community that deserves special recognition. These are just some posts that caught my eye this week.)</p><p>--</p><p>My favorite post this week comes from Josef Ottoson, who describes working with <a href="https://josef.codes/sorting-really-large-files-with-c-sharp/?ref=daveabrock.com">sorting really large files in C#</a>. If you think algorithms have limited real-world applications, think again: after starting with an in-memory application, he compares external merge sort, splitting, and merging. He shows off how he only consumes 32 megabytes when sorting with an external merge sort algorithm, over almost 6 gigabytes with an in-memory solution. (As expected, sorting in memory is a little bit faster.)</p><p>--</p><p>On the heels of the "Focus on F" .NET Conf, F# creator (and the creator of C# 8 and 9 😉) Don Syme has a Github readme called <a href="https://github.com/dsyme/fsharp-presentations/blob/master/design-notes/on-teaching-operators.md?ref=daveabrock.com"><em>What operators and symbols does an F# programmer need to know?</em></a><em> </em>As someone who's been wanting to learn F# for the last few years now, I appreciate the candor: as with C#, there's much of the language that you don't need on a daily basis.</p><p>--</p><p>Over at the Visual Studio Code blog, Chris Dias <a href="https://code.visualstudio.com/blogs/2021/08/05/notebooks?ref=daveabrock.com">writes about the rise of notebooks</a>. School is starting back up soon, but I'm not talking about those: here I'm talking about docs that contain text, executable code, and its output. It provides interesting use cases for learning and development. </p><p>With VS Code, the experience in working with notebooks is a big concern:</p><blockquote>To complete the metaphor, notebooks in VS Code have matured from those awkward teen years into (young) adulthood, confident and strong, with a bright future. Working with VS Code notebooks may take a bit of adjustment if you are moving from Jupyter, but we hope it will be worth it in the end. And, as we always try to do, you can customize the experience through settings.</blockquote><p>--</p><p>We've geeked out about .NET source generators quite a few times in this space. To that end, last week Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/dotnet-source-generators-finding-class-declarations?ref=daveabrock.com">writes about using them to retrieve class declarations from a project</a>. He uses a <code>ISyntaxReceiver</code>, which retrieves the class declarations. </p><p>--</p><p>Jeremy Miller wrote a nice post about <a href="https://jeremydmiller.com/2021/08/04/testing-effectively-with-or-without-mocks-or-stubs/?ref=daveabrock.com">testing effectively with or without mocks or stubs</a>. Are you spending most of your time writing effective tests or simulating data with mocks to avoid writing integration tests? With the advancements in networking and containerization, does it need to be an either/or discussion?</p><p>He writes:</p><blockquote>In the past, we strongly preferred writing “solitary” tests with or without mock objects or other fakes because those tests were reliable and ran fast. That’s still a valid consideration, but I think these days it’s much easier to author more “socialable” tests that might even be using infrastructure like databases or the file system than it was when I originally learned TDD and developer testing. Especially if a team is able to use something like Docker containers to quickly spin up local development environments, I would very strongly recommend writing tests that work through the data layer or call HTTP endpoints in place of pure, Feathers-compliant unit tests.</blockquote><hr><h2 id="did-you-know"><strong>Did </strong>you know?</h2><p>Did you know that in Visual Studio Code, you can make Integrated Terminal sessions appear as editor tabs, instead of taking up valuable space in the panel? Not me.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Today&#39;s <a href="https://twitter.com/code?ref_src=twsrc%5Etfw&ref=daveabrock.com">@code</a> setting: Terminal Default Location<br><br>Use this setting to place newly created integrated terminals in editor tabs instead of in the panel<a href="https://twitter.com/hashtag/code2020?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#code2020</a> <a href="https://t.co/5J4sJdBj4U?ref=daveabrock.com">pic.twitter.com/5J4sJdBj4U</a></p>&mdash; Matt Bierner (@mattbierner) <a href="https://twitter.com/mattbierner/status/1422946680341557250?ref_src=twsrc%5Etfw&ref=daveabrock.com">August 4, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h2 id="quick-housekeeping-note">Quick housekeeping note</h2><p>A quick note: <em>The .NET Stacks</em> is taking a brief break until September. Over the next several weeks, my free time will be extremely limited and I won't be able to devote the time. Thanks as always for your support and I'll be back next month.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Gregor Suttie <a href="https://gregorsuttie.com/2021/08/05/how-to-set-environment-variables-for-use-with-an-azure-function/?ref=daveabrock.com" rel="nofollow">sets environmental variables in an Azure Function</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/08/03/introducing-c-10-record-struct/?ref=daveabrock.com" rel="nofollow">writes about record structs in C# 10</a>.</li><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/08/04/testing-effectively-with-or-without-mocks-or-stubs/?ref=daveabrock.com" rel="nofollow">tests with or without mocks or stubs</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><p>Over at JetBrains, <a href="https://blog.jetbrains.com/dotnet/2021/08/03/dotcover-dotmemory-dottrace-dotpeek-2021-2/?ref=daveabrock.com" rel="nofollow">the v2021.2 releases for dotCover, dotMemory, dotTrace, and dotPeek have arrived</a>. Alexandra Kolesova <a href="https://blog.jetbrains.com/dotnet/2021/08/03/rider-2021-2-released/?ref=daveabrock.com" rel="nofollow">writes about updates to Rider 2021.2</a>, and Alexander Kurakin <a href="https://blog.jetbrains.com/dotnet/2021/08/03/resharper-2021-2-release/?ref=daveabrock.com" rel="nofollow">writes about updates to ReSharper 2021.2</a>.</p><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>In standups this week, ASP.NET talks about <a href="https://www.youtube.com/watch?v=V-rwe2yxh1A&ref=daveabrock.com">logging updates in ASP.NET Core 6</a> and MAUI <a href="https://www.youtube.com/watch?v=oIQfrUfIovk&ref=daveabrock.com">discusses the .NET Upgrade Assistant</a>.</li><li>Shameless plug alert: <a href="https://dotnettips.wordpress.com/2021/07/30/rockin-the-code-world-with-dotnetdave-special-guest-dave-brock/?ref=daveabrock.com">I'll be on David McCarter's "Rockin' the Code World" on Saturday</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Marinko Spasojevic <a href="https://code-maze.com/azure-active-directory-b2c-with-blazor-webassembly-hosted-apps/?ref=daveabrock.com" rel="nofollow">uses Azure Active Directory B2C with Blazor WebAssembly hosted apps</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/synchronous-vs-messaging-when-to-use-which/?ref=daveabrock.com" rel="nofollow">compares using async messages and synchronous requests and responses</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Dennes Torres <a href="https://www.red-gate.com/simple-talk/blogs/careful-net-core-folder-structure/?ref=daveabrock.com" rel="nofollow">warns: be careful with the .NET Core folder structure</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/custom-validation/?ref=daveabrock.com" rel="nofollow">explores custom validation and multi-language resource loading for validation with INotifyDataErrorInfo for XAML applications</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/a-deep-dive-on-stringbuilder-part-4-inserting-and-removing-characters/?ref=daveabrock.com" rel="nofollow">inserts and removes characters using StringBuilder</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/dotnet-source-generators-finding-class-declarations?ref=daveabrock.com" rel="nofollow">uses source generators to find class declarations</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Don Syme <a href="https://github.com/dsyme/fsharp-presentations/blob/master/design-notes/on-teaching-operators.md?ref=daveabrock.com">writes: what operators and symbols do an F# programmer need to know?</a></li><li>Marc Clifton <a href="https://www.codeproject.com/Articles/5309402/Explaining-Csharp-Code-to-Non-Programmers?ref=daveabrock.com" rel="nofollow">explains C# code to non-programmers</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/csharp-10-features-file-level-namespaces/?ref=daveabrock.com" rel="nofollow">explores file-level namespaces in C# 10</a> and also <a href="https://exceptionnotfound.net/bite-size-csharp-10-null-parameter-checking/?ref=daveabrock.com" rel="nofollow">writes about null parameter checking in C# 10</a>.</li><li>Niels Swimberghe levels up on data structures and algorithms as he <a href="https://swimburger.net/blog/dotnet/generic-bubble-sort-in-csharp-dotnet?ref=daveabrock.com" rel="nofollow">writes a generic bubble sort in C#</a>, <a href="https://swimburger.net/blog/dotnet/generic-merge-sort-in-csharp-dotnet?ref=daveabrock.com">works with merge sort</a>, <a href="https://swimburger.net/blog/dotnet/generic-quick-sort-in-csharp-dotnet?ref=daveabrock.com">quick sort</a>, <a href="https://swimburger.net/blog/dotnet/generic-insertion-sort-in-csharp-dotnet?ref=daveabrock.com">insertion sort</a>, <a href="https://swimburger.net/blog/dotnet/generic-binary-search-in-csharp-dotnet?ref=daveabrock.com">binary search</a>, the <a href="https://swimburger.net/blog/dotnet/generic-boyer-moore-horspool-algorithm-in-csharp-dotnet?ref=daveabrock.com">Generic Boyer–Moore–Horspool algorithm</a>, and <a href="https://swimburger.net/blog/dotnet/generic-linear-search-sequential-search-for-a-sequence-in-csharp-dotnet?ref=daveabrock.com">linear/sequential search</a>.</li><li>Mahesh Chand <a href="https://www.c-sharpcorner.com/UploadFile/mahesh/datatable-in-C-Sharp/?ref=daveabrock.com" rel="nofollow">writes about the DataTable in C#</a>.</li><li>Josef Ottosson <a href="https://josef.codes/sorting-really-large-files-with-c-sharp/?ref=daveabrock.com" rel="nofollow">sorts really large files with C#</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/stringly-typed-vs-strongly-typed?ref=daveabrock.com" rel="nofollow">compares stringly typed and strongly typed</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Justin Chadell <a href="https://www.docker.com/blog/introduction-to-heredocs-in-dockerfiles/?ref=daveabrock.com" rel="nofollow">introduces heredocs in Dockerfiles</a>.</li><li>Miroslav Shtilianov <a href="https://www.telerik.com/blogs/designing-load-tests-test-studio-fiddler-6-easy-steps?ref=daveabrock.com" rel="nofollow">designs load tests with Test Studio and Fiddler</a>.</li><li>Shawn Wildermuth <a href="https://wildermuth.com/2021/08/03/Dipping-My-Toe-into-Static-Website-Generators/?ref=daveabrock.com" rel="nofollow">looks at static site generators</a>.</li><li>Chris Dias <a href="https://code.visualstudio.com/blogs/2021/08/05/notebooks?ref=daveabrock.com" rel="nofollow">writes about the coming age of notebooks</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Oren Eini <a href="https://ayende.com/blog/194369-B/open-for-extension-closed-for-modification-as-an-architectural-pattern?Key=f1781074-3cc9-42f2-9982-b84860904968&ref=daveabrock.com" rel="nofollow">writes about "open for extension, closed for modification" as an architectural pattern</a>.</li><li>Beej Burns <a href="https://completedeveloperpodcast.com/fixed-vs-growth-mindset/?ref=daveabrock.com" rel="nofollow">writes about a fixed vs growth mindset</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-defactoring-and-pushing-behavior-down/?ref=daveabrock.com" rel="nofollow">continues writing about domain-driven refactoring</a>.</li><li>George Stocker <a href="https://georgestocker.com/2021/08/06/why-contexts-matter/?ref=daveabrock.com" rel="nofollow">writes about why contexts matter</a>.</li><li>J.B.Rainsberger <a href="https://specflow.org/bdd/bdd-before-you-begin-part-1-2/?ref=daveabrock.com" rel="nofollow">writes about BDD</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The Coding Blocks podcast <a href="https://www.codingblocks.net/podcast/2021-state-of-the-developer-ecosystem/?ref=daveabrock.com" rel="nofollow">talks about the 2021 State of the Developer Ecosystem</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/265?ref=daveabrock.com" rel="nofollow">talks to Maddy Leger</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Getting-started-with-Azure-Static-Web-Apps?ref=daveabrock.com" rel="nofollow">introduces Azure Static Web Apps</a>.</li><li>On .NET <a href="https://channel9.msdn.com/Shows/On-NET/C-Highlights-Immutable-Collections?ref=daveabrock.com" rel="nofollow">talks about immutable collections in C#</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks, #60: 📝Logging improvements in .NET 6 ]]></title>
        <description><![CDATA[ This week, we&#39;re talking about logging improvements that are coming with the .NET 6 release. ]]></description>
        <link>https://www.daveabrock.com/2021/08/08/dotnet-stacks-60/</link>
        <guid isPermaLink="false">6106bb6f2fff1d003b81adab</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 08 Aug 2021 12:14:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/08/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! It's hard to believe it's August already. What are we talking about this week?</p><ul><li><strong>One big thing</strong>: Logging improvements in .NET 6</li><li><strong>The little things</strong>: Notes from the community</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-logging-improvements-in-net-6">One big thing: Logging improvements in .NET 6</h2><p>Over the last few months, we've highlighted some big features coming with .NET 6. Inevitably, there are some features that fly under the radar, including various logging improvements that are coming. Let's talk about a few of them.</p><p>Announced with Preview 4 at the end of May, .NET will <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#microsoft-extensions-logging-compile-time-source-generator">include a new Microsoft.Extensions.Logging compile-time source generator</a>. The <code>Microsoft.Extensions.Logging</code> namespace will expose a <code>LoggerMessageAttribute</code> type that generates "performant logging APIs" at compile-time. (The source code relies on <code>ILogger</code>, thankfully.)</p><p>From the blog post:</p><blockquote>The source generator is triggered when <code>LoggerMessageAttribute</code> is used on <code>partial</code> logging methods. When triggered, it is either able to autogenerate the implementation of the <code>partial</code> methods it’s decorating, or produce compile-time diagnostics with hints about proper usage. The compile-time logging solution is typically considerably faster at run time than existing logging approaches. It achieves this by eliminating boxing, temporary allocations, and copies to the maximum extent possible.</blockquote><p>Rather than using <code>LoggerMessage</code> APIs directly, the .NET team says this approach offers simpler syntax with attributes, the ability to offer warnings as a "guided experience," support for more logging parameters, and more.</p><p>As a quick example, let's say I can't talk to an endpoint. I'd configure a <code>Log</code> class like this:</p><pre><code class="language-csharp">public static partial class Log
{
    [LoggerMessage(EventId = 0, Level = LogLevel.Critical, Message = "Could not reach `{uri}`")]
    public static partial void CouldNotOpenSocket(ILogger logger, string uri);
}</code></pre><p>There is much, much more at the Microsoft doc, <em><a href="https://docs.microsoft.com/en-us/dotnet/core/extensions/logger-message-generator?ref=daveabrock.com">Compile-time logging source generation</a></em>.</p><p>On the topic of HTTP requests, ASP.NET Core has a couple of new logging improvements worth checking out, too. A big one is the introduction of HTTP logging middleware, which can log information about HTTP requests and responses, including the headers and body. According <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0&ref=daveabrock.com">to the documentation</a>, the middleware logs common properties like path, query, status codes, and headers with a call to <code>LogLevel.Information</code>. The HTTP logging middleware is quite configurable: you can filter logging fields, headers to log (you need to explicitly define the headers to include), media type options, and a log limit for the response body. </p><p>This addresses a common use case for web developers. As always, you'll need to keep an eye on possible performance impacts and mask logging sensitive information (like PII data).</p><p>Lastly, with .NET 6 Preview 5 the .NET team <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-5/?ref=daveabrock.com#subcategories-for-better-filtering-of-kestrel-logs">rolled out subcategories for Kestrel log filtering</a>. Previously, verbose Kestrel logging was quite expensive as all of Kestrel has shared the same category name. There are new categories on top of <code>*.Server.Kestrel</code>, including <code>BadRequests</code>, <code>Connections</code>, <code>Http2</code>, and <code>Http3</code>. This allows you to be more selective on which rules you want to enable. As shown in the blog post, if you only want to filter on bad requests, it's as easy as this:</p><pre><code class="language-json">{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Kestrel.BadRequests": "Debug"
    }
  }
}</code></pre><p>If you want to learn more about ASP.NET Core logging improvements in .NET 6, Maryam Ariyan and Sourabh Shirhatti will be <a href="https://www.youtube.com/watch?v=V-rwe2yxh1A&ref=daveabrock.com">talking about it in Tuesday's ASP.NET standup</a>.</p><hr><h2 id="the-little-things-notes-from-the-community">The little things: Notes from the community</h2><p>AutoMapper is a powerful <a href="https://automapper.org/?ref=daveabrock.com">but self-proclaimed "simple little library"</a> for mapping objects. From <a href="https://twitter.com/ShawnWildermuth/status/1421863407830118408?ref=daveabrock.com">Shawn Wildermuth on Twitter</a>, Dean Dashwood has written about <a href="https://github.com/ddashwood/AutoMapperBlog/blob/main/AutoMapper%20Blog.md?ref=daveabrock.com"><em>Three Things I Wish I Knew About AutoMapper Before Starting</em></a>. It centers around subtleties when working with dependency injection in models, saving changed and nested data, and changing the models. It's actually a GitHub repo with a writeup and some code samples—highly recommended.</p><hr><p>Sometimes one sentence does the trick: <a href="https://github.com/cezarypiatek/msbuild-cheatsheet?ref=daveabrock.com">Cezary Piątek has a nice MsBuild cheatsheet on GitHub</a>.</p><hr><p>This week, Mike Hadlow wrote about <a href="https://mikehadlow.com/posts/standalone-consoleloggerprovider/?ref=daveabrock.com">creating a standalone </a><code><a href="https://mikehadlow.com/posts/standalone-consoleloggerprovider/?ref=daveabrock.com">ConsoleLoggerProvider</a></code><a href="https://mikehadlow.com/posts/standalone-consoleloggerprovider/?ref=daveabrock.com"> in C#</a>. If you want to create a standalone provider to avoid working with dependency injection and hosting, Mike found an ... interesting ... design. He develops a simple no-op implementation.<br></p><hr><p>Well, it's been 20 years since the Agile Manifesto, and Al Tenhundfeld celebrates it with the article <a href="https://www.simplethread.com/agile-at-20-the-failed-rebellion/?ref=daveabrock.com"><em>Agile at 20: The Failed Rebellion</em></a>. I think we can all agree that (1) everybody wants to claim they are Agile, and (2) Agile is a very, um, flexible word—nobody is really <em>doing </em>Agile (at least according to the Manifesto). He explores why; an interesting read. </p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Oren Eini <a href="https://ayende.com/blog/194337-B/system-threading-tasks-task-isnt-an-execution-unit?Key=885fdaff-cc07-4ab1-adad-c278fe7de264&ref=daveabrock.com" rel="nofollow">writes that System.Threading.Tasks.Task isn’t an execution unit</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/a-deep-dive-on-stringbuilder-part-3-converting-chunks-to-a-string-with-tostring/?ref=daveabrock.com" rel="nofollow">continues his deep dive on StringBuilder</a>, and <a href="https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-net-part-3-how-appending-works-and-the-stringbuilder-expands?ref=daveabrock.com">so does Steve Gordon</a>.</li><li>Al Tenhundfeld <a href="https://www.simplethread.com/agile-at-20-the-failed-rebellion/?ref=daveabrock.com" rel="nofollow">speaks the truth on Agile</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Dapr v1.3 <a href="https://blog.dapr.io/posts/2021/07/27/dapr-v1.3-is-now-available/?ref=daveabrock.com" rel="nofollow">is now available</a>.</li><li>Michael Hawker <a href="https://devblogs.microsoft.com/ifdef-windows/welcome-to-the-community-toolkit?ref=daveabrock.com" rel="nofollow">introduces the Community Toolkit</a>.</li><li>Uno Platform <a href="https://platform.uno/blog/uno-platform-3-9-net-6-mobile-vs-2022-winui-plus-xaml-trimming-for-50-wasm-aot-size-reduction/?ref=daveabrock.com" rel="nofollow">shows off improvements with 3.9</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/07/29/marten-the-generic-host-builder-in-net-core-and-why-this-could-be-the-golden-age-for-oss-in-net/?ref=daveabrock.com" rel="nofollow">writes about Marten, the generic host builder in .Net Core, and more</a>.</li><li>Mike Brind <a href="https://www.mikesdotnetting.com/article/356/i-am-writing-a-book-about-razor-pages?ref=daveabrock.com" rel="nofollow">is writing a book about Razor Pages</a>.</li><li>Sha Ma <a href="https://www.infoq.com/articles/github-monolith-microservices/?ref=daveabrock.com" rel="nofollow">writes about GitHub's journey from monoliths to microservices</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-the-net-open-source-project?ref=daveabrock.com" rel="nofollow">posts a discussion about the .NET open source project</a>.</li><li>Matthew MacDonald asks: <a href="https://medium.com/young-coder/what-if-github-copilot-worked-like-a-real-programmer-337581375aae?ref=daveabrock.com" rel="nofollow">what if GitHub Copilot worked like a real programmer?</a></li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=m6KXIk7S6GE&ref=daveabrock.com">talks to Vahid Farahmandian about gRPC and .NET 5</a>.</li><li>For community standups: ASP.NET <a href="https://www.youtube.com/watch?v=JuIq7mU50jA&ref=daveabrock.com">talks to Isaac Abraham about F#</a>, and Entity Framework <a href="https://www.youtube.com/watch?v=Q3Ove-2Uh94&ref=daveabrock.com">talks about OData</a>.</li><li>Check out all the <a href="https://www.youtube.com/watch?v=i3qEhwcG7ps&ref=daveabrock.com">Focus on F# sessions on YouTube</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>The Code Maze blog <a href="https://code-maze.com/onion-architecture-in-aspnetcore/?ref=daveabrock.com" rel="nofollow">writes about Onion Architecture in ASP.NET Core</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/07/26/securing-asp-net-core-razor-pages-web-apis-with-azure-b2c-external-and-azure-ad-internal-identities/?ref=daveabrock.com" rel="nofollow">secures ASP.NET Core Razor Pages and Web APIs with Azure B2C External and Azure AD internal identities</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Mike Hadlow <a href="https://mikehadlow.com/posts/standalone-consoleloggerprovider/?ref=daveabrock.com" rel="nofollow">creates a standalone ConsoleLoggerProvider</a>.</li><li>Santosh Hari <a href="https://santoshhari.wordpress.com/2021/07/26/using-app-secrets-in-dotnetcore-console-applications/?ref=daveabrock.com" rel="nofollow">uses app secrets in .NET Core console apps</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>April Edwards <a href="https://devblogs.microsoft.com/devops/comparing-azure-static-web-apps-vs-azure-webapps-vs-azure-blob-storage-static-sites?ref=daveabrock.com" rel="nofollow">compares Azure Static Web Apps, Azure WebApps, and Azure Blob Storage Static Sites</a>.</li><li>Mark Heath <a href="https://markheath.net/post/serverless-sliding-scale?ref=daveabrock.com" rel="nofollow">writes about the serverless sliding scale</a>.</li><li>John Kilmister <a href="https://www.blueboxes.co.uk/getting-started-with-serverless-signalr-and-azure-functions?ref=daveabrock.com" rel="nofollow">gets started with serverless SignalR and Azure Functions</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/07/24/configure-cloudflare-to-work-with-your-azure-domain-registration/?ref=daveabrock.com" rel="nofollow">configures Cloudflare to work with Azure domains</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/07/27/introducing-c-10extended-property-patterns/?ref=daveabrock.com" rel="nofollow">writes about extended property patterns in C# 10</a>.</li><li>Gergely Sinka <a href="https://developer.okta.com/blog/2021/07/28/toggle-feature-flags-csharp?ref=daveabrock.com" rel="nofollow">toggles functionality in C# with feature flags</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/07/28/efcore6-preview6.aspx?ref=daveabrock.com" rel="nofollow">writes about Entity Framework Core 6</a>.</li><li>Rachel Appel <a href="https://blog.jetbrains.com/dotnet/2021/07/27/blazor-debugging-improvements-in-rider-2021-2/?ref=daveabrock.com" rel="nofollow">writes about Blazor debugging improvements in Rider 2021.2</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/redis-cli-connection-uri-with-stackexchangeredis?ref=daveabrock.com" rel="nofollow">writes an extension method that parses a redis-cli connection string for the StackExchange.Redis library</a>.</li><li>Dmitry Lyalin <a href="https://devblogs.microsoft.com/visualstudio/speed-up-your-dotnet-and-cplusplus-development-with-hot-reload-in-visual-studio-2022?ref=daveabrock.com" rel="nofollow">writes about hot reload in Visual Studio 2022</a>.</li><li>Kat Cosgrove <a href="https://www.pulumi.com/blog/kubernetes-fundamentals-part-one/?ref=daveabrock.com" rel="nofollow">writes about Kubernetes fundamentals</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/creating-a-dapper-helper-csharp-class-to-generate-parameterized-sql-inserts-and-updates/?ref=daveabrock.com" rel="nofollow">creates a Dapper helper C# class to generate parameterized SQL</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Leomaris Reyes <a href="https://askxammy.com/replicating-fashion-ui-in-xamarin-forms/?ref=daveabrock.com" rel="nofollow">reproduces a fashion UI in Xamarin</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/expandable-paragraph-control-in-xamarin-forms/?ref=daveabrock.com" rel="nofollow">creates an expandable paragraph control in Xamarin</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Oren Eini <a href="https://ayende.com/blog/194274-B/responsibility-abdication-the-path-to-create-flexible-business-system?Key=f7efcebb-71e0-4050-868b-c8df437cd574&ref=daveabrock.com" rel="nofollow">writes about flexible business systems</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/message-driven-architecture-to-decouple-a-monolith/?ref=daveabrock.com" rel="nofollow">uses a message-driven architecture to decouple a monolith</a>.</li><li>Charles Humble <a href="https://thenewstack.io/the-future-of-microservices-more-abstractions/?ref=daveabrock.com" rel="nofollow">writes about the future of microservices</a>.</li><li>Suzanne Scacca <a href="https://www.telerik.com/blogs/tips-using-heatmaps-audit-web-design?ref=daveabrock.com" rel="nofollow">uses heatmaps to audit web design</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/clean-code-vs-performance?ref=daveabrock.com" rel="nofollow">explores the tradeoffs of performance and clean code</a>.</li><li>Ben Nadel <a href="https://www.bennadel.com/blog/4089-feature-flags-shift-the-balance-of-power-away-from-designers.htm?ref=daveabrock.com" rel="nofollow">writes about feature flags</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-extracting-domain-services/?ref=daveabrock.com" rel="nofollow">continues his series on domain-driven refactoring</a>.</li><li>Ian Cartwright, Rob Horn, &amp; James Lewis <a href="https://martinfowler.com/articles/patterns-legacy-displacement/feature-parity.html?ref=daveabrock.com" rel="nofollow">write about feature parity</a>.</li><li>InfoQ talks to <a href="https://www.infoq.com/podcasts/michael-perry-crdts-art-of-immutable-architecture/?ref=daveabrock.com" rel="nofollow">Michael Perry about immutable architecture, the CAP theorem, and CRDTs</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-205-polly-with-bryan-hogan/?ref=daveabrock.com" rel="nofollow">talks to Bryan Hogan about Polly</a>.</li><li>Adventures in .NET <a href="https://devchat.tv/adventures-in-dotnet/global-reach-of-net-net-079/?ref=daveabrock.com" rel="nofollow">talks about the global reach of .NET</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/264?ref=daveabrock.com" rel="nofollow">talks about FOSS and .NET MAUI Web with Ooui</a>.</li><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-81-gremlinq-with-daniel-weber/?ref=daveabrock.com" rel="nofollow">discusses Gremlinq With Daniel Weber</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/amanda-silver-on-whats-coming-for-developers-episode-151?ref=daveabrock.com" rel="nofollow">talks about what's coming for developers</a>.</li><li>Scott Hanselman <a href="https://www.hanselminutes.com/799/learn-f-to-write-succinct-performant-and-correct-code-with-don-syme?ref=daveabrock.com" rel="nofollow">talks to Don Syme about F#</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-387-Azure-Arc?ref=daveabrock.com" rel="nofollow">talks about Azure Arc</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=m2ouoDx8_wI&ref=daveabrock.com" rel="nofollow">works on accessibility testing with Playwright and Axe</a>.</li><li>Luis Quintanilla <a href="https://www.youtube.com/watch?v=yGzu0iDuMNQ&ref=daveabrock.com" rel="nofollow">rolls out a nice "intro to F#" video series</a>.</li><li>Shawn Wildermuth <a href="https://wildermuth.com/2021/07/25/Coding-Shorts-Coding-Shorts-Changes-to-Coming-to-Startup-in-NET-6?ref=daveabrock.com" rel="nofollow">talks about changes coming to Startup in .NET 6</a>.</li><li>On .NET talks <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-ValueTask?ref=daveabrock.com" rel="nofollow">about ValueTask in C#</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #59: 🎇 When your Copilot is mostly right ]]></title>
        <description><![CDATA[ Let&#39;s talk about GitHub Copilot and a new JSON serialization source generator. ]]></description>
        <link>https://www.daveabrock.com/2021/08/01/dotnet-stacks-59/</link>
        <guid isPermaLink="false">60fac0a18d4bf3004832502b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 01 Aug 2021 10:53:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/08/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another week, all. I hope your Monday is off to a good start. </p><p>If you follow me on Twitter, you may have heard I <a href="https://twitter.com/daveabrock/status/1418027622148321282?ref=daveabrock.com">got attacked by six bees last week</a>. I'm fine but appreciate some of you reaching out with comments about whether I'm still "buzzing around somewhere" or "minding my own beeswax" or "ooh, that stings" or even sending memes of a guy with a beard made of bees. </p><p>Here's what <s>hive</s> I've got for you this week:</p><ul><li><strong>One big thing</strong>: Thoughts on GitHub Copilot</li><li><strong>The little things</strong>: A new source generator for JSON serialization, F# getting some love</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-thoughts-on-github-copilot">One big thing: Thoughts on GitHub Copilot</h2><p>Have you caught all the buzz about <a href="https://copilot.github.com/?ref=daveabrock.com">GitHub Copilot</a>? It's been out in private preview for about a month and I've been checking it out. Marketed by GitHub as "your AI pair programmer," it provides predictions for your code—either as a single line or even an entire function. It's based on GPT-3, a "<a href="https://en.wikipedia.org/wiki/GPT-3?ref=daveabrock.com">deep-learning model that uses deep learning to produce human like text</a>." </p><p>To <a href="https://blog.scottlogic.com/2021/07/03/github-copilot-first-thoughts.html?ref=daveabrock.com">quote Colin Ebehardt</a>:</p><blockquote>Copilot is based on Codex, a new model which is a derivative of GPT3, which has been trained on vast quantities of open source code from GitHub. It is integrated directly with VSCode in order to generate suggestions based on a combination of the current context (i.e. your code), and the ‘knowledge’ it has acquired during the training process.</blockquote><p>There's a ton of examples online from amazed developers. For example, you can enter a comment like <code>// Call GitHub API</code> and Copilot will create a function that calls the GitHub API for you. Of course, this led to some snarky comments about AI taking our jobs. If you're concerned about that, I'd ask you to look at some of the code Copilot spits out. It isn't perfect, but it learns from you ... and does an OK job. To quote philosopher Brian Fantana: "<a href="https://www.youtube.com/watch?v=pjvQFtlNQ-M&t=2s&ref=daveabrock.com">60% of the time, it works every time</a>." </p><p>Copilot has massive potential to improve developer workflow and efficiency. For example, how many times do you have to ask Google how to do something you haven't done in a while? Let's say you haven't called <code>HttpClient</code> in a while, or you want to read from a CSV file. You search how to do it, find official docs or Stack Overflow, and go back to your editor and do your best. What if you can cut out all that manual work and generate that code in a few keystrokes? You can focus on the problem you're solving and not on "how do I" tasks. As a smart and experienced developer, you'll know that you'll need to understand the code and tweak it as needed. I do worry about those who won't. It's been easy to blindly introduce code since the invention of the Internet, of course, but doing it from your editor cranks it up a few notches. </p><p>From Matthew MacDonald's <a href="https://medium.com/young-coder/github-copilot-fatally-flawed-or-the-future-of-software-development-390c30afbc97?ref=daveabrock.com">excellent piece on Copilot</a>:</p><blockquote>As long as you need to spend effort reviewing every piece of suggested code, and as long as there is no way to separate a rock-solid implementation from something fuzzier and riskier, the value of Copilot drops dramatically. Not only will it save less time, but it risks introducing elementary mistakes that a less experienced programmer might accept, like using float for a currency variable.</blockquote><p>This offering—which will eventually be sold by Microsoft—spends a lot of the reputational capital Microsoft has been building with developers since they started embracing open-source software. While it fits with Microsoft's mission to own the developer experience—from GitHub and NPM to Azure and VS Code, just to name a few—I've seen some Microsoft skeptics viewing this as the company cashing in on the goodwill with the community. While you can't be shocked to see a company mining its free service's public data for eventual profit, there are quite a few licensing and legal challenges that need further clarification (saying "the code belongs to you" in its FAQs might not get by a company's legal department).</p><p>Even so, I think Copilot will eventually turn into a powerful tool that can help to automate the painful parts of programming.</p><hr><h2 id="the-little-things-a-new-source-generator-for-json-serialization-f-getting-some-love">The little things: A new source generator for JSON serialization, F# getting some love</h2><p>While it's easy to highlight the new .NET stuff like hot reload and AOT compilation, it's just as important to write about the stuff we do every day: like serializing and deserializing JSON. Is it exciting? No. It is fun? Also no. It's something we do all the time, though—so <a href="https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/?ref=daveabrock.com">it was nice to see Microsoft roll out a new <code>System.Text.Json</code> source generator</a>.</p><p>We've <a href="https://www.daveabrock.com/2020/09/05/dotnet-stacks-15/">talked about source generators before</a>, but a refresher: its code that runs during compilation and can produce additional files that are compiled together with the rest of your code. It’s a compilation step that generates code <em>for you</em> based on your code. It <a href="https://github.com/amis92/csharp-source-generators?ref=daveabrock.com">creates a lot of possibilities</a>. This provides an alternative for expensive reflection code, which traditionally leads to slow startup and memory issues.</p><p>This new source generator works with <code>JsonSerializer</code> (and does not break existing implementations, don't worry). From the <a href="https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/?ref=daveabrock.com">post on the topic</a>:</p><blockquote>The approach the JSON source generator takes to provide these benefits is to move the runtime inspection of JSON-serializable types to compile-time, where it generates a static model to access data on the types, optimized serialization logic using <code>Utf8JsonWriter</code> directly, or both.</blockquote><p>In the end, moving much of this from runtime to compile-time will help with throughput, memory, and assembly trimming capabilities. The trimming is a big one. The generator can shed a lot of unused code and dependencies. </p><p> I think the post does a good job of outlining the capabilities and the <a href="https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/?ref=daveabrock.com#versioning">rationale for introducing yet another set of APIs</a>. </p><hr><p>It's been nice to see F# getting some love lately. Microsoft's latest .NET Conf will be <em>Focus on F#</em>, <a href="https://focus.dotnetconf.net/?ref=daveabrock.com">which will take place on Thursday</a>. Last week, the .NET Docs Show <a href="https://www.youtube.com/watch?v=gLSUpH6fonY&ref=daveabrock.com">held an F# AMA</a> and Microsoft <a href="https://techcommunity.microsoft.com/t5/azure-developer-community-blog/new-learn-modules-write-your-first-code-in-f-write-your-first-f/ba-p/2569795?ref=daveabrock.com">introduced its first F# Learn modules</a>. Even if you're a C# lifer, it's hard to argue against the impact of functional languages such as F#. As C# has spent the last few major releases introducing constructs like pattern matching, records, and features that focus on immutability, these are features languages like F# have enjoyed for years. </p><p>As for <em>Focus on F#</em>, there's <a href="https://focus.dotnetconf.net/agenda?ref=daveabrock.com">a lot of nice stuff on the agenda</a>. I'm looking forward to seeing F# creator Don Syme teaching Python creator Guido van Rossum F# from scratch. For more information on F# and its context within the C# ecosystem, I recommend brushing up on my interviews last year with <a href="https://www.daveabrock.com/2020/09/19/dev-discussions-isaac-abraham/">Isaac Abraham</a> and <a href="https://www.daveabrock.com/2020/09/26/dev-discussions-phillip-carter/">Phillip Carter</a>.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Matthew MacDonald asks: <a href="https://medium.com/young-coder/github-copilot-fatally-flawed-or-the-future-of-software-development-390c30afbc97?ref=daveabrock.com" rel="nofollow">is GitHub Copilot fatally flawed or the future of software development?</a></li><li>Dave Brock <a href="https://www.telerik.com/blogs/work-unhandled-exceptions-gracefully-blazor-server-dotnet-6-error-boundaries?ref=daveabrock.com" rel="nofollow">works with Blazor Error Boundaries</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/a-deep-dive-on-stringbuilder-part-2-appending-strings-built-in-types-and-lists/?ref=daveabrock.com" rel="nofollow">continues his deep dive on StringBuilder</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-july-2021?ref=daveabrock.com" rel="nofollow">recaps their July release</a>.</li><li>James Montemagno <a href="https://devblogs.microsoft.com/xamarin/xamarin-essentials-1-7-and-introducing-net-maui-essentials?ref=daveabrock.com" rel="nofollow">introduces .NET MAUI Essentials</a>.</li><li>JetBrains has released <a href="https://blog.jetbrains.com/dotnet/2021/07/22/resharper-rider-2021-1-5/?ref=daveabrock.com" rel="nofollow">ReSharper 2021.1.5 and Rider 2021.1.5</a>.</li><li>The Azure Portal team <a href="https://techcommunity.microsoft.com/t5/azure-portal/azure-portal-june-2021-update?ref=daveabrock.com" rel="nofollow">provides their June update</a>.</li><li>Layomi Akinrinade <a href="https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/?ref=daveabrock.com">introduces the new <code>System.Text.Json</code> source generator</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>JetBrains releases <a href="https://blog.jetbrains.com/blog/2021/07/16/the-state-of-developer-ecosystem-2021/?ref=daveabrock.com" rel="nofollow"><em>The State of Developer Ecosystem 2021</em></a>.</li><li>Microsoft now has <a href="https://devblogs.microsoft.com/visualstudio/join-the-visual-studio-2022-for-mac-private-preview?ref=daveabrock.com" rel="nofollow">a private preview for Visual Studio 2022 for Mac</a>.</li><li>Microsoft has rolled out <a href="https://techcommunity.microsoft.com/t5/azure-developer-community-blog/new-learn-modules-write-your-first-code-in-f-write-your-first-f/ba-p/2569795?ref=daveabrock.com" rel="nofollow">some Learn modules on F#</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=gLSUpH6fonY&ref=daveabrock.com">hosts an F# AMA</a>.</li><li>Three community standups this week: Desktop <a href="https://www.youtube.com/watch?v=38pVA5iXDeE&ref=daveabrock.com">provides updates</a>, Machine Learning <a href="https://www.youtube.com/watch?v=sYMdHMlHS4I&ref=daveabrock.com">holds office hours</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=Eq0Jvhk0o1Y&ref=daveabrock.com">continues its architecture discussions</a>.</li><li>Reminder: <a href="https://focus.dotnetconf.net/?ref=daveabrock.com">Focus on F# is on July 29</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/blazor-and-cancelling-asynchronous-calls-with-cancellationtokensource?ref=daveabrock.com" rel="nofollow">works with Blazor and canceling async calls with CancellationTokenSource</a>, and <a href="https://blog.jetbrains.com/dotnet/2021/07/19/getting-started-with-asp-net-core-and-grpc/?ref=daveabrock.com" rel="nofollow">gets started with ASP.NET Core and gRPC</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/07/20/using-an-asp-net-core-ihostedservice-to-run-azure-service-bus-subscriptions-and-consumers/?ref=daveabrock.com" rel="nofollow">uses an ASP.NET Core IHostedService to run Azure Service Bus subscriptions and consumers</a>.</li><li>Tomasz Pęczek <a href="https://www.tpeczek.com/2021/07/aspnet-core-6-and-iasyncenumerable.html?ref=daveabrock.com" rel="nofollow">compares async streamed JSON vs NDJSON in .NET 6</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-app-roles-with-azure-active-directory-and-blazor-webassembly-hosted-apps/?ref=daveabrock.com" rel="nofollow">uses app roles with Azure AD and Blazor WebAssembly hosted apps</a>.</li><li>Hassan Habib <a href="https://devblogs.microsoft.com/odata/up-running-w-odata-in-asp-net-6?ref=daveabrock.com" rel="nofollow">works with OData in ASP.NET Core 6</a>.</li><li>Nikhil Mohan <a href="https://www.cncf.io/blog/2021/07/19/think-grpc-when-you-are-architecting-modern-microservices/?ref=daveabrock.com" rel="nofollow">advocates for gRPC</a>.</li><li>Mike Brind <a href="https://www.mikesdotnetting.com/article/355/css-isolation-in-razor-pages?ref=daveabrock.com" rel="nofollow">works on CSS isolation for Razor Pages</a>.</li><li>Jon Hilton <a href="https://jonhilton.net/blazor-refit/?ref=daveabrock.com" rel="nofollow">uses Refit with Blazor</a>.</li><li>Bruno Sonnino <a href="https://blogs.msmvps.com/bsonnino/2021/07/17/transforming-your-asp-net-core-mvc-app-into-a-pwa/?ref=daveabrock.com" rel="nofollow">transforms an ASP.NET Core MVC app into a PWA</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><p>Mike Hadlow <a href="https://mikehadlow.com/posts/service-collection-object-graph-writer/?ref=daveabrock.com" rel="nofollow">creates an Microsoft.Extensions.DependencyInjection object graph writer</a>.</p><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Thomas Maurer <a href="https://www.youtube.com/watch?v=4su7dW8603Q&ref=daveabrock.com" rel="nofollow">writes about getting started with Azure Arc</a>.</li><li>Matias Quaranta <a href="https://devblogs.microsoft.com/cosmosdb/asp-net-session-state-cache-provider?ref=daveabrock.com" rel="nofollow">uses Cosmos DB as an ASP.NET session state and caching provider</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/07/22/introducing-c-10-constant-interpolated-strings/?ref=daveabrock.com" rel="nofollow">writes about constant interpolated strings in C# 10</a>, <a href="https://anthonygiretti.com/2021/07/23/introducing-c-10-mix-declarations-and-expressions-in-a-deconstruction/?ref=daveabrock.com" rel="nofollow">uses C# 10 to mix declarations and expressions in deconstruction</a>, and <a href="https://anthonygiretti.com/2021/07/19/introducing-c-10-seal-overriden-tostring-method-on-records/?ref=daveabrock.com" rel="nofollow">seals overridden ToString() method on records</a>.</li><li>Chris Noring <a href="https://dev.to/azure/write-your-first-code-in-f-36gl?ref=daveabrock.com" rel="nofollow">writes about getting started with F#</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Sayed Hashimi <a href="https://devblogs.microsoft.com/visualstudio/design-your-web-forms-apps-with-web-live-preview-in-visual-studio-2022?ref=daveabrock.com" rel="nofollow">designs Web Forms apps with Web Live Preview in Visual Studio 2022</a>.</li><li>Gergely Sinka <a href="https://developer.okta.com/blog/2021/07/16/dotnet-elastisearch?ref=daveabrock.com" rel="nofollow">uses Elasticsearch for .NET</a>.</li><li>Ivan Porta <a href="https://www.c-sharpcorner.com/article/azure-pipelines-yaml-templates/?ref=daveabrock.com" rel="nofollow">explores Azure Pipelines YAML templates</a>.</li><li>Charris Herrera <a href="https://stackify.com/top-visual-studio-profiling-tools/?ref=daveabrock.com" rel="nofollow">writes about the top Visual Studio profiling tools</a>.</li><li>Niels Swimberghe <a href="https://www.twilio.com/blog/protect-phone-number-proxying-twilio-phone-numbers-twilio-voice-twilio-functions?ref=daveabrock.com">proxies phone numbers with Twilio Programmable Voice and Twilio Functions</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Dotnetsafer recaps <a href="https://dev.to/dotnetsafer/top-5-net-maui-new-features-1mlb?ref=daveabrock.com" rel="nofollow">some new MAUI features</a>.</li><li>Giorgi Dalakishvili <a href="https://developer.okta.com/blog/2021/07/21/xamarin-forms-pkce-sdk?ref=daveabrock.com" rel="nofollow">works on Xamarin Forms auth with PKCE</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Over at <em>martinfowler.com</em>, <a href="https://martinfowler.com/articles/patterns-legacy-displacement/?ref=daveabrock.com" rel="nofollow">they write about patterns of legacy displacement</a> and <a href="https://martinfowler.com/articles/patterns-legacy-displacement/extract-product-lines.html?ref=daveabrock.com" rel="nofollow">a discussion about extracting product lines</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/what-is-code-review-guidelines-best-practices/?ref=daveabrock.com" rel="nofollow">writes about best practices for code reviews</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/how-to-maximize-testing-4-truths?ref=daveabrock.com" rel="nofollow">writes about the 4 truths of testing</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/cleancodetips/03-use-pronounceable-names?ref=daveabrock.com" rel="nofollow">has another clean coding tip</a>.</li><li>Swizec Teller <a href="https://swizec.com/blog/what-i-learned-from-software-engineering-at-google/?ref=daveabrock.com" rel="nofollow">writes about reading <em>Software Engineering at Google</em></a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-long-methods/?ref=daveabrock.com" rel="nofollow">continues writing about domain-driven refactoring</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-skills-and-learning?ref=daveabrock.com" rel="nofollow">hosts a discussion about skills and learning</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-204-comet-and-net-maui-with-james-clancey/?ref=daveabrock.com" rel="nofollow">talks about Comet and .NET MAUI with James Clancey</a>.</li><li>The Coding Blocks podcast <a href="https://www.codingblocks.net/podcast/what-is-github-copilot/?ref=daveabrock.com" rel="nofollow">talks about GitHub Copilot</a>.</li><li>The Working Code podcast asks: <a href="https://www.bennadel.com/blog/4081-working-code-podcast-episode-032-what-comes-after-senior-developer.htm?ref=daveabrock.com" rel="nofollow">what comes after senior developer?</a></li><li>The AWS Developers Podcast <a href="https://soundcloud.com/awsdevelopers/episode-006-cloud-9-and-productive-dev-environments-with-richard-h-boyd?ref=daveabrock.com" rel="nofollow">talks about productive dev environments</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-386-Static-Web-Apps?ref=daveabrock.com" rel="nofollow">talks to Daria Grigoriu about Azure Static Web Apps</a>.</li><li>Coding After Work <a href="http://codingafterwork.com/2021/07/18/episode-59-bunit-tdd-and-sci-fi-with-egil-hansen/?ref=daveabrock.com" rel="nofollow">talks to Egil Hansen about bUnit and TDD</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Learn Live <a href="https://channel9.msdn.com/Shows/Learn-Live/Work-with-users-groups-and-roles-in-custom-apps-and-APIs?ref=daveabrock.com" rel="nofollow">works with Microsoft Identity</a>.</li><li>The On .NET Show talks about <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Exhaustive-case-guards?ref=daveabrock.com" rel="nofollow">exhaustive case guards in C#</a> and <a href="https://www.youtube.com/watch?v=EUyXU2NJGGk&ref=daveabrock.com">functional-first programming</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #58: 📃 6 things about .NET 6 Preview 6 ]]></title>
        <description><![CDATA[ This week, we talk about .NET 6 Preview 6, Visual Studio 2022, and abstracting away Kubernetes. ]]></description>
        <link>https://www.daveabrock.com/2021/07/25/dotnet-stacks-58/</link>
        <guid isPermaLink="false">60f1f46c8846a6003bd4f480</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 25 Jul 2021 13:36:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/07/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another wonderful week. I just learned you can put a timestamp in Notepad by hitting F5. I saw this by reading a blog post from 2002. How's <em>your </em>Monday?</p><p>Here's what we have going on in #58:</p><ul><li><strong>One big thing</strong>: 6 things about .NET 6 Preview 6</li><li><strong>The little things</strong>: Visual Studio 2022 Preview 2, abstracting Kubernetes</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-6-things-about-net-6-preview-6">One big thing: 6 things about .NET 6 Preview 6</h2><p>Last week, the .NET team rolled out .NET 6 Preview 6. Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-6/?ref=daveabrock.com">has the main blog post</a>.  Dan Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6?ref=daveabrock.com">writes about ASP.NET Core updates</a>, Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-6-configure-conventions?ref=daveabrock.com">updates us on EF Core 6</a>, and David Ortinau <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-6/?ref=daveabrock.com">covers .NET MAUI</a>. Preview 6 is the second to last preview release of .NET 6. It appears to be a smaller release, with Preview 7 being bigger, as it's the last preview release.  .NET 6 will end up with seven preview releases, then two RC releases (the latter of which should come with go-live licenses). </p><p>The releases will be winding down soon, as Richard Lander says: "<em>We’ll soon be addressing only the most pressing feedback, approaching the same bug bar that we use for servicing releases. If you’ve been holding on to some feedback or have yet to try .NET 6, please do now. It’s your last chance to influence the release.</em>"</p><p>If you want the full details, you can check out the links above—as for me, I'd like to highlight six things that caught my eye.</p><p><strong>Sync-over-async thread performance</strong>. The sync-over-async pattern—which means using synchronous functionality asynchronously—is a common source of performance degradation and thread starvation. A <a href="https://github.com/dotnet/runtime/pull/53471?ref=daveabrock.com">new change in Preview 6</a> will improve the rate of default thread injection when the only blocking work on the thread pool is sync-over-async.</p><p><strong>New functionality for working with parameters in ASP.NET Core</strong>. The ASP.NET Core team released two new features that help when working with components in ASP.NET Core.</p><p>The first involves <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/?ref=daveabrock.com#required-blazor-component-parameters">required Blazor component parameters</a>. You do this by using a new <code>[EditorRequired]</code> attribute, like this:</p><pre><code class="language-csharp">[EditorRequired]
[Parameter]
public string Title { get; set; }</code></pre><p>This functionality is enforced at design time and when building—it's important to note it isn't enforced at runtime and won't guarantee the value of the parameter won't be null.</p><p>The next feature now supports <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/?ref=daveabrock.com#optional-parameters-for-view-components-tag-helpers">optional parameters for view component tag helpers</a> in ASP.NET Core. With this update, you no longer need to specify a value for an optional parameter as a tag helper attribute.</p><p><strong>WebSocket compression</strong>. ASP.NET Core <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/?ref=daveabrock.com#optional-parameters-for-view-components-tag-helpers">now supports WebSocket compression</a>. This can yield tremendous performance benefits with comes with <em>a ton</em> of caveats. It's disabled by default because enabling it over encrypted connections can make your app subject to attacks. As such, you should only enable it when you know sensitive information isn't being passed around. If that isn't clear enough, the setting is called <code>DangerousEnableCompression</code>. No, <a href="https://github.com/dotnet/aspnetcore/pull/32600/files?ref=daveabrock.com#diff-c980da9f0c086f0f16ca6d9b1208731773bef1262623a0c6947a733c6512e67fR32">seriously</a>.</p><p><strong>Minimal API improvements</strong>. We've talked about <a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com">.NET 6 Minimal APIs</a> quite a bit—so much you're probably sick of me talking about them. Even so, the team keeps building them out and Preview 6 brings some enhancements.</p><p>First, you can now integrate those APIs <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/?ref=daveabrock.com#openapi-support-in-minimal-apis">with OpenAPI (Swagger) support</a>. You can do this using dependency injection (DI) or middleware. Here's an example using the DI method:</p><pre><code class="language-csharp">builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen(c =&gt;
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Description = "My Swagger", Version = "v1" });
});</code></pre><p>Second, you can now inject services into the <code>[FromServices]</code> attribute. Previously, you <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/?ref=daveabrock.com#inject-services-into-minimal-apis-without-fromservices-attribute">needed to do something like this</a>:</p><pre><code class="language-csharp">app.MapGet("/movies", async ([FromServices] MovieDbContext db) =&gt;
{
    return await db.Movies.ToListAsync();
});</code></pre><p>  And now it's this:</p><pre><code class="language-csharp">app.MapGet("/movies", async (MovieDbContext db) =&gt;
{
    return await db.Movies.ToListAsync();
});</code></pre><p><strong>Pre-convention model configuration</strong>. From Preview 6 of EF Core, they've released pre-convention model configuration. From <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-6-configure-conventions/?ref=daveabrock.com">the announcement</a>, Jeremy Likness says it's part of "finding ways to enhance model building so that it can more efficiently figure out what is an entity type and what is not." As more types are mapped, it can be painful to exclude types as entity types (and bringing all that overhead into a model) and reverting types from being entity types in certain situations.</p><p>You can now use a <code>ConfigureConventions</code> override to avoid the hassle of configuring every entity. In Jeremy's example, if you want to always store strings as byte arrays, you can use the override instead:</p><pre><code class="language-csharp">protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
  {
      configurationBuilder.Properties&lt;string&gt;()
          .HaveConversion&lt;byte[]&gt;()
          .HaveMaxLength(255);

      configurationBuilder.IgnoreAny&lt;INonPersisted&gt;();
  }</code></pre><p><strong>.NET MAUI packaged as workload installation</strong>. With .NET 6, Xamarin is merging into the .NET Multi-platform UI (MAUI). MAUI is aiming to be a cross-platform framework for creating mobile and desktop apps with C# and XAML. I don't mention it much here in the newsletter for two reasons—I can't speak about it intelligently because I have no experience with it, and I'm allergic to XAML. The last time I opened a XAML file I got a fever and was in bed for three days. </p><p>Even so, there's a lot of great work going into it, and Preview 6 <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-6/?ref=daveabrock.com">marks the first time MAUI will be shipped as a workload installation</a>. Like the rest of .NET, you can use SDK workloads to enable specific workloads. In MAUI's case, the team is introducing <code>maui</code>, <code>maui-mobile</code>, and <code>maui-desktop</code> workloads, and soon Visual Studio 2022 will include these workloads in the installer.</p><p>MAUI is <a href="https://github.com/dotnet/maui/wiki/Status?ref=daveabrock.com">getting close to feature-complete</a> for .NET 6. In this release, the team is rolling out <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-6/?ref=daveabrock.com#gestures">gesture recognizers</a>, <a href="https://github.com/dotnet/maui/wiki/Status?ref=daveabrock.com">clipping region enhancements</a>, and <a href="https://github.com/dotnet/maui/wiki/Status?ref=daveabrock.com">native alerts</a>. Check out <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-6?ref=daveabrock.com">the announcement</a> to learn more. </p><hr><h2 id="the-little-things-visual-studio-2022-preview-2-abstracting-kubernetes">The little things: Visual Studio 2022 Preview 2, abstracting Kubernetes</h2><p>Since we're on the topic of previews, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-2-is-out/?ref=daveabrock.com">Visual Studio 2022 Preview 2 is out</a>. Preview 2 is fully localized and ships with over a dozen language packs.</p><p>In this update, VS 2022 includes new "Live Preview" experiences with XAML and web apps, which allows you to kiss goodbye to the ancient-feeling recompile-and-run workflow. They are also touting a new Web Live Preview, to allow you to speed up your workflow, with instant updates when working with CSS or data controls. (I suppose we're happy to have it, even if it's an expected feature from modern IDEs these days.) Lastly, this update introduces Force Run, a way to run your app to a specific point that ignores other breakpoints or exceptions. (If you work on C++, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-2-is-out/?ref=daveabrock.com">check out the post</a>. C++ isn't a .NET language, so I don't write about it here.)</p><hr><p>When I see click-baity articles with headlines like <a href="https://thenewstack.io/why-developers-should-learn-kubernetes/?ref=daveabrock.com"><em>Why Developers Should Learn Kubernetes</em></a>, I can't help but cringe. Thankfully, the article is better than the headline suggests—but even so, it's a lot to suggest developers should know the ins and outs of pods, containers, networking, DNS, and load balancing. There's a difference between asking developers to Shift Left, and making them become SRE experts.</p><p>Kubernetes gets a lot of grief: it can be extreme overkill and it incurs a steep learning curve. Even so, containerization (and orchestrating these containers) is here to stay, but we should be providing developers with more abstractions over Kubernetes to make it a more PaaS-like experience. Microsoft is <a href="https://thenewstack.io/microsoft-takes-practical-approach-to-kubernetes-management/?ref=daveabrock.com">working on their part</a>, and don't be surprised to see Azure (and other clouds) make investments in this space.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-4">🔥 The Top 4</h3><ul><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-procedural-beginnings/?ref=daveabrock.com" rel="nofollow">continues his series on domain-driven refactoring</a>.</li><li>Peter Kuhn <a href="https://www.mistergoodcat.com/post/thoughts-on-microsoft-and-blazor?ref=daveabrock.com" rel="nofollow">conveys his thoughts on Microsoft and Blazor</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/a-deep-dive-on-stringbuilder-part-1-the-overall-design-and-first-look-at-the-internals/?ref=daveabrock.com" rel="nofollow">starts a deep dive on StringBuilder</a>.</li><li>Iris Classon writes that <a href="https://dotnetfoundation.org/blog/2021/07/14/net-foundation-election-2021-nominations-open?ref=daveabrock.com">the nominations are open for the .NET Foundation Board of Directors 2021 election</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-6/?ref=daveabrock.com" rel="nofollow">announces .NET 6 Preview 6</a>. Daniel Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6?ref=daveabrock.com" rel="nofollow">walks through ASP.NET Core updates,</a> Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-6-configure-conventions?ref=daveabrock.com" rel="nofollow">announces updates for EF Core 6</a>, and David Ortinau <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-6/?ref=daveabrock.com" rel="nofollow">writes about .NET MAUI updates for .NET 6 Preview 6</a>.</li><li>Visual Studio 2022 Preview 2 <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-2-is-out?ref=daveabrock.com" rel="nofollow">has arrived</a>.</li><li>Kayla Cinnamon <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-10-release/?ref=daveabrock.com" rel="nofollow">rolls out the Windows Terminal Preview 1.10 release</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Joe Guadagno <a href="https://www.josephguadagno.net/2021/07/15/software-architecture-with-c-sharp-and-dot-net-5-book-review?ref=daveabrock.com" rel="nofollow">reviews <em>Software Architecture with C# 9 and .NET 5</em></a>.</li><li>Brandon Minnick <a href="https://devblogs.microsoft.com/xamarin/the-future-of-xamarin-community-toolkit/?ref=daveabrock.com" rel="nofollow">writes about the future of the Xamarin Community Toolkit</a>.</li><li>The Focus on F# <a href="https://focus.dotnetconf.net/agenda?ref=daveabrock.com" rel="nofollow">agenda is out</a>.</li><li>JetBrains is looking <a href="https://blog.jetbrains.com/dotnet/2021/07/15/get-a-reward-for-sharing-your-dottrace-or-dotmemory-experience/?ref=daveabrock.com" rel="nofollow">for feedback on dotMemory and dotTrace</a>.</li><li>For community standups: .NET Tooling <a href="https://www.youtube.com/watch?v=0i0d7CncwGU&ref=daveabrock.com">updates on the latest</a>, ASP.NET talks <a href="https://www.youtube.com/watch?v=hKxciQMxueI&ref=daveabrock.com">Powered4.tv</a> and Entity Framework <a href="https://www.youtube.com/watch?v=Zhy5antRDJk&ref=daveabrock.com">visualizes database query plans</a>. </li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=jWdMLP13vVo&ref=daveabrock.com">talks to Isaac Abraham about F#</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Peter Kuhn <a href="https://www.mistergoodcat.com/post/blazor-server-apps-in-mvc-subfolders?ref=daveabrock.com" rel="nofollow">works on Blazor Server apps in MVC subfolders</a>.</li><li>Jay Krishna Reddy <a href="https://www.c-sharpcorner.com/article/jwt-validation-and-authorization-in-net-5-0/?ref=daveabrock.com" rel="nofollow">creates and validates a JWT token in .NET 5.0</a>.</li><li>Cody Merritt Anhorn <a href="https://nu-codyanhorn-tech.azurewebsites.net/blog/blazor-anchor-tag-scroll-to?ref=daveabrock.com" rel="nofollow">uses Blazor to scroll to a hash anchor on the current page</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/permission-based-security-aspnet-webapi/?ref=daveabrock.com" rel="nofollow">works on permission-based security for ASP.NET Web APIs</a>.</li><li>Sam Xu <a href="https://devblogs.microsoft.com/odata/api-versioning-extension-with-asp-net-core-odata-8/?ref=daveabrock.com" rel="nofollow">introduces an API versioning extension with ASP.NET Core OData 8</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/how-to-use-button-onclick-event-blazor-webassembly?ref=daveabrock.com" rel="nofollow">uses the button onclick event in Blazor WebAssembly</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Bar Arnon <a href="http://blog.i3arnon.com/2021/07/12/async-linq-operator/?ref=daveabrock.com" rel="nofollow">writes about the evolution of an async LINQ operator</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2021/07/14/directory-build-props-c-sharp-9-for-all/?ref=daveabrock.com" rel="nofollow">works with Directory.Build.props and C# 9</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/194177-A/postmortem-the-case-of-the-pauses-the-fault-and-the-gc?Key=01e08ec5-4e36-4293-a58a-1343784f8d0e&ref=daveabrock.com" rel="nofollow">investigates a performance issue</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/debuggerdisplay-attribute?ref=daveabrock.com" rel="nofollow">works with the DebuggerDisplay attribute</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Aaron Powell <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/calling-static-web-apps-authenticated-api-endpoints/ba-p/2536870?ref=daveabrock.com" rel="nofollow">calls Azure Static Web Apps authenticated API endpoints</a>, <a href="https://www.aaron-powell.com/posts/2021-07-11-functions-cosmosdb-output-bindings-and-fsharp/?ref=daveabrock.com" rel="nofollow">works with Azure Functions, F# and CosmosDB Output Bindings</a>, and <a href="https://www.aaron-powell.com/posts/2021-07-16-adding-user-profiles-to-swa/?ref=daveabrock.com" rel="nofollow">adds user profiles to Azure Static Web Apps</a>.</li><li>Chloe Condon <a href="https://dev.to/azure/got-bots-2-making-bots-with-azure-logic-apps-47nm?ref=daveabrock.com" rel="nofollow">makes bots with Azure Logic Apps</a>.</li><li>Milan Milanović <a href="https://milan.milanovic.org/post/protect-web-apis-using-azure/?ref=daveabrock.com" rel="nofollow">secures the modern development lifecycle with Microsoft Identity</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>The Code Maze blog <a href="https://code-maze.com/c-tips-to-improve-code-quality-and-performance/?ref=daveabrock.com" rel="nofollow">writes about C# tips for code quality and performance</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-9-New-Features-Reduce-Boilerplate-Constructor-Code-with-Init-Only-Property-Setters?ref=daveabrock.com" rel="nofollow">works on init-only property setters in C#</a>.</li><li>Mike Hadlow <a href="https://mikehadlow.com/posts/simple-console-loop/?ref=daveabrock.com" rel="nofollow">writes a simple console periodic loop in C#</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/target-typed-new-expressions-in-csharp-9-are-they-the-future?ref=daveabrock.com" rel="nofollow">writes about target typed new expressions in C# 9</a>.</li><li>Anthony Giretti writes about <a href="https://anthonygiretti.com/2021/07/18/introducing-c-10-global-usings-example-with-asp-net-core-6/?ref=daveabrock.com">global usings in .NET 6 and ASP.NET Core</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Domagoj Vidovic <a href="https://dev.to/domagojvidovic/11-git-commands-i-use-every-day-43eo?ref=daveabrock.com" rel="nofollow">runs through common Git commands</a>.</li><li>Pam Selle <a href="https://thewebivore.com/testing-a-command-inside-a-docker-container-or-getting-an-interactive-session/?ref=daveabrock.com" rel="nofollow">tests a command inside a docker container</a>.</li><li>Erik Heemskerk <a href="https://www.erikheemskerk.nl/nuke-build-components/?ref=daveabrock.com" rel="nofollow">creates reusable build scripts with NUKE components</a>.</li><li>The Kubernetes Blog <a href="https://kubernetes.io/blog/2021/07/14/upcoming-changes-in-kubernetes-1-22/?ref=daveabrock.com" rel="nofollow">outlines Kubernetes API and feature removals In 1.22</a>.</li><li>Stephane Eyskens <a href="https://techcommunity.microsoft.com/t5/azure-developer-community-blog/hardening-an-asp-net-container-running-on-kubernetes/ba-p/2542224?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com" rel="nofollow">hardens an ASP.NET container running on Kubernetes</a>.</li><li>Steve Tidwell <a href="https://thenewstack.io/why-developers-should-learn-kubernetes/?ref=daveabrock.com" rel="nofollow">writes how developers should learn Kubernetes</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/07/12/a-better-way-to-discover-apis-with-the-new-endpoints-window/?ref=daveabrock.com" rel="nofollow">shows off a better way to discover APIs with JetBrains Rider</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Scott Carey <a href="https://www.arnnet.com.au/article/689569/how-5-companies-got-their-developers-care-about-cloud-costs/?ref=daveabrock.com" rel="nofollow">writes about how companies got their developers to care about cloud costs</a>.</li><li>Suzanne Scacca <a href="https://www.telerik.com/blogs/6-things-to-make-websites-appear-more-trustworthy?ref=daveabrock.com" rel="nofollow">writes about building trustworthy websites</a>.</li><li>Al Tenhundfeld <a href="https://www.simplethread.com/git-commit-message-101/?ref=daveabrock.com" rel="nofollow">talks about writing good Git commit messages</a>.</li><li>Josef Ottoson <a href="https://josef.codes/dealing-with-access-tokens-in-dotnet/?ref=daveabrock.com" rel="nofollow">deals with access tokens in .NET</a>.</li><li>Ron Jeffries asks: <a href="https://ronjeffries.com/articles/021-01ff/fix-scrum-01/?ref=daveabrock.com" rel="nofollow">Can scrum be fixed?</a></li><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-procedural-beginnings/?ref=daveabrock.com" rel="nofollow">continues his series on domain-driven refactoring</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/07/10/mutation-testing/?ref=daveabrock.com" rel="nofollow">tries out mutation testing</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-385-Cloud-Native-apps-in-Azure?ref=daveabrock.com" rel="nofollow">discusses cloud-native apps</a>.</li><li>The Unhandled Exception podcast <a href="https://unhandledexceptionpodcast.com/posts/0019-blazor/?ref=daveabrock.com" rel="nofollow">talks to Chris Sainty about Blazor</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/262?ref=daveabrock.com" rel="nofollow">talks about GitHub Copilot</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-203-nuget-and-tiktok-with-jon-douglas/?ref=daveabrock.com" rel="nofollow">talks to Jon Douglas</a>.</li><li>Scott Hanselman <a href="https://www.hanselminutes.com/797/new-ways-to-teach-computer-science-with-maria-naggaga?ref=daveabrock.com" rel="nofollow">talks to Maria Naggaga about teaching computer science</a>.</li><li>The No Dogma Podcast <a href="https://nodogmapodcast.bryanhogan.net/155-david-guida-event-sourcing/?ref=daveabrock.com">talks to David Guida about event sourcing</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Azure-Cosmos-DB-cache-serverless-MongoDB-and-Managed-Apache-Cassandra?ref=daveabrock.com" rel="nofollow">talks about several Azure Cosmos DB updates</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Using-SQL-Data-Sync-for-Bidirectional-Data-Replication-in-SQL-Server-and-Azure-SQL-DBs?ref=daveabrock.com" rel="nofollow">uses SQL Data Sync</a>.</li><li>The On .NET Show <a href="https://www.youtube.com/watch?v=IRvDGPbxdTs&ref=daveabrock.com" rel="nofollow">discusses commands, queries, and Clean Architecture</a>, <a href="https://www.youtube.com/watch?v=tnepPn3Py8s&ref=daveabrock.com">positional pattern matching</a>, and <a href="https://www.youtube.com/watch?v=Z7KVKHZsWyM&ref=daveabrock.com">explores Spark and ML .NET with F#</a>.</li><li>Technology and Friends <a href="https://www.davidgiard.com/2021/07/12/JasonBockOnMutationTesting.aspx?ref=daveabrock.com" rel="nofollow">talks to Jason Bock about mutation testing</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Unhandled Exceptions in Blazor Server with Error Boundaries ]]></title>
        <description><![CDATA[ Let’s look at error boundaries in Blazor, a new feature that allows you to handle Blazor Server unhandled exceptions more easily. We’ll learn what error boundaries are, and what they are not. ]]></description>
        <link>https://www.daveabrock.com/2021/07/21/blazor-error-boundaries/</link>
        <guid isPermaLink="false">60d136759caef9003b75e3f9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 21 Jul 2021 09:54:52 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1555861496-0666c8981751?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fEVSUk9SfGVufDB8fHx8MTYyNTUzODQyMQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post originally appeared on the <a href="https://www.telerik.com/blogs/work-unhandled-exceptions-gracefully-blazor-server-dotnet-6-error-boundaries?ref=daveabrock.com">Telerik Developer Blog</a>.</em></p><p>In Blazor—especially Blazor Server—there is no such thing as a small unhandled exception. When Blazor Server detects an unhandled exception from a component, ASP.NET Core treats it as a fatal exception. Why? </p><p>Blazor Server apps implement data processing statefully so that the client and server <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/security/server/threat-mitigation?view=aspnetcore-5.0&ref=daveabrock.com">can have a "long-lived relationship</a>." To accomplish this, Blazor Server creates a circuit server-side, which indicates to the browser how to respond to events and what to render. When an unhandled exception occurs, Blazor Server treats it as a fatal error because the circuit hangs in an undefined state, which can potentially lead to usability or security problems.</p><p>As a result, your app is as good as dead, loses its state, and your users are met with an undesirable <em>An unhandled error has occurred</em> message, with a link to reload the page. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/07/unhandled-exception.png" class="kg-image" alt loading="lazy" width="1840" height="1293" srcset="https://www.daveabrock.com/content/images/size/w600/2021/07/unhandled-exception.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/07/unhandled-exception.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/07/unhandled-exception.png 1600w, https://www.daveabrock.com/content/images/2021/07/unhandled-exception.png 1840w" sizes="(min-width: 720px) 720px"></figure><p>In many cases, unhandled exceptions can be out of a developer's control—like when you have an issue with third-party code. From a practical perspective, it's not realistic to assume components will <em>never </em>throw. </p><p>Here's an example that <a href="https://github.com/dotnet/aspnetcore/issues/26953?ref=daveabrock.com">a Blazor developer</a> posted on GitHub: let's say I've got two components: <code>MyNicelyWrittenComponent</code>, which I wrote, and a third-party component, <code>BadlyWrittenComponent</code>, which I did not write. (Badly written components rarely identify themselves so well, but I digress.)</p><pre><code class="language-csharp">&lt;div&gt;
   &lt;MyNicelyWrittenComponent&gt;
   &lt;BadlyWrittenComponent Name="null"&gt;
&lt;/div&gt;

</code></pre><p>What if the third-party code is coded like this?</p><pre><code class="language-csharp">@code {
    [Parameter] public string Name { get; set; }
}
&lt;p&gt;@Name.ToLower()&lt;/p&gt;</code></pre><p>While I can reasonably expect <code>BadlyWrittenComponent</code> to blow up, the circuit is broken, and I can't salvage <code>MyNicelyWrittenComponent</code>. This begs the question: if I get an unhandled exception from a single component, why should my entire app die? As a Blazor developer, you're left spending a lot of time hacking around this by putting <code>try</code> and <code>catch</code> blocks around every single method of your app, leading to performance issues—especially when thinking about cascading parameters.</p><p> If you look at our front-end ecosystems, like React, they <a href="https://reactjs.org/docs/error-boundaries.html?ref=daveabrock.com">use Error Boundaries</a> to catch errors in a component tree and display a fallback UI when a failure occurs for a single component. When this happens, the errors are isolated to the problematic component, and the rest of the application remains functional.</p><p>Fear no more: with .NET 6 Preview 4, the ASP.NET Core team introduced <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-error-boundaries">Blazor error boundaries</a>. Inspired by Error Boundaries in React, it attempts to catch recoverable errors that can't permanently corrupt state—and like the React feature, it also renders a fallback UI.</p><p>From the <a href="https://github.com/dotnet/aspnetcore/issues/30940?ref=daveabrock.com#issue-831895900">Error Boundaries design document</a>, the team notes that its primary goals are to allow developers to provide fallback UIs for component subtrees if an exception exists, allow developers to provide cleaner fallback experiences, and provide more fine-grained control over how to handle failures. This capability won't catch all possible exceptions but most common scenarios such as the various lifecycle methods (like <code>OnInitializedAsync</code>, <code>OnParametersSetAsync</code>, and <code>OnAfterRenderAsync</code> ,  and rendering use cases with <code>BuildRenderTree</code>.</p><p>In this post, I'll help you understand what Error Boundaries are—and just as importantly, what they aren't.</p><h2 id="get-started-add-error-boundaries-to-the-main-layout">Get Started: Add Error Boundaries to the Main Layout</h2><p>To get started, let's use a quick example. Let's say I know a guy—<a href="https://twitter.com/Telerik/status/1408063115875389455?ref=daveabrock.com">let's call him MAUI Man</a>—that runs a surf shop. In this case, MAUI Man has a Blazor Server app where he sells surfboards and t-shirts. His developer, Ed, wrote a <code>ProductService</code> that retrieves this data.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/07/maui-man-surf-shop.jpg" class="kg-image" alt loading="lazy" width="2000" height="881" srcset="https://www.daveabrock.com/content/images/size/w600/2021/07/maui-man-surf-shop.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/07/maui-man-surf-shop.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/07/maui-man-surf-shop.jpg 1600w, https://www.daveabrock.com/content/images/size/w2400/2021/07/maui-man-surf-shop.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>Let's say the Surfboard API is having problems. Before the error boundary functionality was introduced, my component would fail to process the unhandled exception, and I'd see the typical error message at the bottom of the page.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/07/maui-man-old-error-message.jpg" class="kg-image" alt loading="lazy" width="1882" height="1520" srcset="https://www.daveabrock.com/content/images/size/w600/2021/07/maui-man-old-error-message.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/07/maui-man-old-error-message.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/07/maui-man-old-error-message.jpg 1600w, https://www.daveabrock.com/content/images/2021/07/maui-man-old-error-message.jpg 1882w" sizes="(min-width: 720px) 720px"></figure><p>Let's use the new <code>ErrorBoundary</code> component instead. To do this, navigate to the <code>MainLayout.razor</code> file. (If you aren't familiar, the <code>MainLayout</code> component is your Blazor app's default layout.) In this file, surround the <code>@Body</code> declaration with the<code>ErrorBoundary</code> component. If an unhandled exception is thrown, we'll render a fallback error UI.</p><pre><code class="language-html">@inherits LayoutComponentBase

&lt;div class="page"&gt;
    &lt;div class="sidebar"&gt;
        &lt;NavMenu /&gt;
    &lt;/div&gt;

    &lt;div class="main"&gt;
        &lt;div class="content px-4"&gt;
          &lt;ErrorBoundary&gt;
            @Body
          &lt;/ErrorBoundary&gt;    
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>On the home page where we call the Surfboard API, we see the default error UI. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/07/surfboards-error.jpg" class="kg-image" alt loading="lazy" width="1830" height="937" srcset="https://www.daveabrock.com/content/images/size/w600/2021/07/surfboards-error.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/07/surfboards-error.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/07/surfboards-error.jpg 1600w, https://www.daveabrock.com/content/images/2021/07/surfboards-error.jpg 1830w" sizes="(min-width: 720px) 720px"></figure><p>The default UI does not include any content other than  <em>An error has occurred</em>. Even in development scenarios, you won't see stack trace information. Later in this post, I'll show you how you can include it.</p><p>This UI renders an empty <code>&lt;div&gt;</code> with a <code>blazor-error-boundary</code> CSS class. You can override this in your global styles if desired, or even replace it altogether. In the following example, I can customize my <code>ErrorBoundary</code> component. In this example, I include the <code>@Body</code> inside a <code>RenderFragment</code> called <code>ChildContent</code>. This content displays when no error occurs. Inside <code>ErrorContent</code>—which, for the record, is <em>technically </em>a <code>RenderFragment&lt;Exception&gt;</code>—displays when there's an unhandled error.</p><pre><code class="language-html">&lt;ErrorBoundary&gt;
  &lt;ChildContent&gt;
     @Body
  &lt;/ChildContent&gt;
  &lt;ErrorContent&gt;
     &lt;p class="my-custom-class"&gt;Whoa, sorry about that! While we fix this problem, buy some shirts!&lt;/p&gt;
  &lt;/ErrorContent&gt;
&lt;/ErrorBoundary&gt; </code></pre><p>How else can you work with the <code>ErrorBoundary</code>? Let's explore.</p><h2 id="exploring-the-errorboundary-component">Exploring the ErrorBoundary Component	</h2><p>Aside from the <code>ChildContent</code> and <code>ErrorContent</code> fragments, the out-of-the-box <code>ErrorBoundary</code> component also provides a <code>CurrentException</code> property—it's an <code>Exception</code> type you can use to get stack trace information. You can use this to add to your default error message (which should only be exposed in development environments for security reasons).</p><p>Most importantly, the <code>ErrorBoundary</code> component allows you to call a <code>Recover</code> method, which resets the error boundary to a "non-errored state." By default, the component <a href="https://github.com/dotnet/aspnetcore/blob/223d6e527cc98ce13fe45e4e14911013dd5ad807/src/Components/Components/src/ErrorBoundaryBase.cs?ref=daveabrock.com#L31">handles up to 100 errors</a> through its <code>MaximumErrorCount</code> property. The <code>Recover</code> method <a href="https://github.com/dotnet/aspnetcore/blob/223d6e527cc98ce13fe45e4e14911013dd5ad807/src/Components/Components/src/ErrorBoundaryBase.cs?ref=daveabrock.com#L42">does three things for you</a>: it resets the component's error count to <code>0</code>, clears the <code>CurrentException</code> and calls <code>StateHasChanged</code>. The <code>StateHasChanged</code> call <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-5.0&ref=daveabrock.com#state-changes-statehaschanged">notifies components that the state has changed</a> and typically causes your component to be rerendered.</p><p>We can use this to browse to our <code>Shirts</code> component when we have an issue with the Surfboard API (or the other way around). Since the boundary is set in the main layout, at first we see the default error UI on every page. We can use the component's <code>Recover</code> method to reset the error boundaries on subsequent page navigations.</p><pre><code class="language-csharp">@code {
    ErrorBoundary errorBoundary;

    protected override void OnParametersSet()
    {
        errorBoundary?.Recover();
    }
}</code></pre><p>As a best practice, you'll typically want to define your error boundaries at a more granular level. Armed with some knowledge about how the <code>ErrorBoundary</code> component works, let's do just that.</p><h2 id="dealing-with-bad-data">Dealing with Bad Data</h2><p>It's quite common to experience issues with getting and fetching data, whether it's from a database directly or from APIs we're calling (either internal or external APIs).  This can happen for a variety of reasons: from a flaky connection, an API's breaking changes, or just inconsistent data.</p><p>In my <code>ShirtList</code> component, we call off to a <code>ShirtService</code>. Here's what I have in <code>ShirtList.razor.cs</code>:</p><pre><code class="language-csharp">using ErrorBoundaries.Data;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ErrorBoundaries.Pages
{
    partial class ShirtList : ComponentBase
    {
        public List&lt;Shirt&gt; ShirtProductsList { get; set; } = new List&lt;Shirt&gt;();

        [Inject]
        public IProductService ShirtService { get; set; }

        protected override async Task OnInitializedAsync()
        {
            ShirtProductsList = await ShirtService.GetShirtList();
        }
    }
}</code></pre><p>In my <code>ShirtList.razor</code> file, I'm iterating through the <code>ShirtProductsList</code> and displaying it. (If you're worked in ASP.NET Core before you've done this anywhere between five million and ten million times.)</p><pre><code class="language-html">&lt;table class="table"&gt;
 &lt;thead&gt;
     &lt;tr&gt;
         &lt;th&gt;ID&lt;/th&gt;
         &lt;th&gt;Name&lt;/th&gt;
         &lt;th&gt;Color&lt;/th&gt;
         &lt;th&gt;Price&lt;/th&gt;
     &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
     @foreach (var board in ShirtProductsList)
     {  
         &lt;tr&gt;
            &lt;td&gt;@board.Id&lt;/td&gt;
            &lt;td&gt;@board.Name&lt;/td&gt;
            &lt;td&gt;@board.Color&lt;/td&gt;
            &lt;td&gt;@board.Price&lt;/td&gt;
          &lt;/tr&gt;   
        }
  &lt;/tbody&gt;
&lt;/table&gt;</code></pre><p>Instead, I can wrap the display in an <code>ErrorBoundary</code> and catch the error to display a message instead. (In this example, to avoid repetition I'll show the <code>&lt;tbody&gt;</code> section for the Razor component.)</p><pre><code class="language-csharp">&lt;tbody&gt;
   @foreach (var board in ShirtProductsList)
   {
        &lt;ErrorBoundary @key="@board"&gt;
            &lt;ChildContent&gt;
                &lt;tr&gt;
                   &lt;td&gt;@board.Id&lt;/td&gt;
                   &lt;td&gt;@board.Name&lt;/td&gt;
                   &lt;td&gt;@board.Color&lt;/td&gt;
                   &lt;td&gt;@board.Price&lt;/td&gt;
                 &lt;/tr&gt;   
             &lt;/ChildContent&gt;
             &lt;ErrorContent&gt;
                 Sorry, I can't show @board.Id because of an internal error.
             &lt;/ErrorContent&gt;
         &lt;/ErrorBoundary&gt;        
     }
&lt;/tbody&gt;</code></pre><p>In this situation, the <code>ErrorBoundary</code> can take a <code>@key</code>, which in my case is the individual <code>Surfboard</code>, which lives in the  <code>board</code> variable. The <code>ChildContent</code> will display the data just as before, assuming I don't get any errors. If I encounter any unhandled errors, I'll use <code>ErrorContent</code> to define the contents of the error message. In my case, it provides a more elegant solution than placing generic <code>try</code> and <code>catch</code> statements all over the place.</p><h2 id="what-error-boundaries-isnt">What Error Boundaries <em>Isn't</em></h2><p>I hope this gentle introduction to Blazor Error Boundaries has helped you understand how it all works. We should also talk about which use cases aren't a great fit for Error Boundaries.</p><p>Blazor Error Boundaries is not meant to be a global exception handling mechanism for any and all unhandled errors you encounter in your apps. You should be able to log all uncaught exceptions using the <code>ILogger</code> interface. </p><p>While you <em>can</em> mark all your components with error boundaries and ignore exceptions, you should take a more nuanced approach to your application's error handling. Error Boundaries are meant for control over your specific component's unhandled exceptions and not a quick way to manage failures throughout your entire application.  </p><h2 id="conclusion">Conclusion</h2><p>While it's been nice to see the growth of Blazor over the several years, it's also great to see how the ASP.NET Core team isn't afraid to add new features by looking around at other leading front-end libraries—for example, the CSS isolation was <a href="https://vue-loader.vuejs.org/guide/scoped-css.html?ref=daveabrock.com#scoped-css">inspired by Vue</a> and Error Boundaries is <a href="https://reactjs.org/docs/error-boundaries.html?ref=daveabrock.com">taking cues from what React has done</a>. Not only is Blazor built on open web technologies, but it's also not afraid to look around the community to make things better.</p><p>Do you find this useful? Will it help you manage component-specific unhandled exceptions? Let us know in the comments.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #57: 🧐 Taking a look at Blazor Error Boundaries ]]></title>
        <description><![CDATA[ This week, let&#39;s take a look at Blazor Error Boundaries and Minimal API improvements. ]]></description>
        <link>https://www.daveabrock.com/2021/07/18/dotnet-stacks-57/</link>
        <guid isPermaLink="false">60e8a79a139437003e98f0b5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 18 Jul 2021 18:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/07/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Good morning, everybody. I hope everyone has had a good last couple of weeks, as I took last week off to celebrate Independence Day here in the United States. </p><p>Here's what we have this week:</p><ul><li>The big thing: Taking a look at Blazor Error Boundaries</li><li>The little things: .NET Foundation elections, Minimal API improvements, pining to help with OSS?</li><li>Last week in the .NET world</li></ul><hr><h2 id="the-big-thing-taking-a-look-at-blazor-error-boundaries">The big thing: Taking a look at Blazor Error Boundaries</h2><p>This weekend, I finished writing a piece on <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-error-boundaries">Blazor error boundaries</a>. It'll be published in a week or two, so here's a preview for you.</p><p>Looking at Blazor Server apps: when an unhandled exception occurs, Blazor Server treats it as a fatal error because the circuit hangs in an undefined state, which can potentially lead to usability or security problems. As a result, your app is as good as dead, loses its state, and your users are met with an undesirable <em>An unhandled error has occurred</em> message, with a link to reload the page.</p><p>This begs the question: if I get an unhandled exception from a single component, why should my entire app die? As a Blazor developer, you're left spending a lot of time hacking around this by putting <code>try</code> and <code>catch</code> blocks around every single method of your app, leading to performance issues—especially when thinking about cascading parameters. Blazor developers <a href="https://reactjs.org/docs/error-boundaries.html?ref=daveabrock.com">look longingly at React's Error Boundaries</a> and wonder when we get to have nice things.</p><p>With .NET 6 Preview 4, you can. Inspired by Error Boundaries in React, it attempts to catch recoverable errors that can't permanently corrupt state—and like the React feature, it also renders a fallback UI. This capability won't catch all possible exceptions but most common scenarios such as the various lifecycle methods (like <code>OnInitializedAsync</code>, <code>OnParametersSetAsync</code>, and <code>OnAfterRenderAsync</code> ,  and rendering use cases with <code>BuildRenderTree</code>.</p><p>The new <code>ErrorBoundary</code> component provides a <code>ChildContent</code> fragment (what to display when all goes well), an <code>ErrorContent</code> fragment (what to display when it doesn't), and a <code>CurrentException</code> property so you can capture exception details. </p><p>Most importantly, the <code>ErrorBoundary</code> component allows you to call a <code>Recover</code> method, which resets the error boundary to a "non-errored state." By default, the component <a href="https://github.com/dotnet/aspnetcore/blob/223d6e527cc98ce13fe45e4e14911013dd5ad807/src/Components/Components/src/ErrorBoundaryBase.cs?ref=daveabrock.com#L31">handles up to 100 errors</a> through its <code>MaximumErrorCount</code> property. The <code>Recover</code> method <a href="https://github.com/dotnet/aspnetcore/blob/223d6e527cc98ce13fe45e4e14911013dd5ad807/src/Components/Components/src/ErrorBoundaryBase.cs?ref=daveabrock.com#L42">does three things for you</a>: it resets the component's error count to <code>0</code>, clears the <code>CurrentException</code> and calls <code>StateHasChanged</code>. The <code>StateHasChanged</code> call <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-5.0&ref=daveabrock.com#state-changes-statehaschanged">notifies components that the state has changed</a> and typically causes your component to be rerendered.</p><p>Here's an example:</p><pre><code class="language-csharp">@code {
    ErrorBoundary errorBoundary;

    protected override void OnParametersSet()
    {
        errorBoundary?.Recover();
    }
}</code></pre><p>For another example, let's say you have a component that calls off to an API. Here, I'm getting a list of surfboards. I can wrap the data fetching in an <code>ErrorBoundary</code>.</p><pre><code class="language-html">&lt;tbody&gt;
   @foreach (var board in ShirtProductsList)
   {
        &lt;ErrorBoundary @key="@board"&gt;
            &lt;ChildContent&gt;
                &lt;tr&gt;
                   &lt;td&gt;@board.Id&lt;/td&gt;
                   &lt;td&gt;@board.Name&lt;/td&gt;
                   &lt;td&gt;@board.Color&lt;/td&gt;
                   &lt;td&gt;@board.Price&lt;/td&gt;
                 &lt;/tr&gt;   
             &lt;/ChildContent&gt;
             &lt;ErrorContent&gt;
                 Sorry, I can't show @board.Id because of an internal error.
             &lt;/ErrorContent&gt;
         &lt;/ErrorBoundary&gt;        
     }
&lt;/tbody&gt;</code></pre><p>Blazor Error Boundaries is not meant to be a global exception handling mechanism for any and all unhandled errors you encounter in your apps. You should be able to log all uncaught exceptions using the <code>ILogger</code> interface.</p><p>While you <em>can</em> mark all your components with error boundaries and ignore exceptions, you should take a more nuanced approach to your application's error handling. Error Boundaries are meant for control over your specific component's unhandled exceptions and not a quick way to manage failures throughout your entire application. What do you think?</p><hr><h2 id="the-little-things-net-foundation-elections-minimal-api-improvements-pining-to-help-with-a-project">The little things: .NET Foundation elections, Minimal API improvements, pining to help with a project?</h2><p>The .NET Foundation will be holding elections next month for two upcoming Board seats. If you've <a href="https://dotnetfoundation.org/about/election/?ref=daveabrock.com">made it to the Elections page</a>, you'll see my face as I'm on the Election Committee.</p><p>The .NET Foundation serves the general .NET community by promoting .NET in general, advocating .NET OSS, promoting .NET across a wider community of developers, supporting .NET community events, and offering administrative support to member projects. This is an organization that runs separately from Microsoft.</p><p>As a Board member, you'd help to run the .NET Foundation by deciding how the money is spent, decide which projects join the foundation, and much more. If you're interested in running for a seat, let me know and I'll get you started.</p><hr><p>We've covered<a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com"> Minimal APIs in .NET 6</a> a time or two. Prioritizing functions over classes, it's a route to simple APIs that many call ".NET Express"—I like the name because it describes getting right to the point and <a href="http://expressjs.com/?ref=daveabrock.com">one of the inspirations</a>. </p><p>The examples have mostly been a little "Hello World"-ish. ASP.NET Core architect David Fowler shows that it's coming along:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">We&#39;re making lots of progress on the minimal API experience in .NET 6. Lots of features are finally coming together. <a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://t.co/oOlNOMiquk?ref=daveabrock.com">pic.twitter.com/oOlNOMiquk</a></p>&mdash; David Fowler 🇧🇧💉💉 (@davidfowl) <a href="https://twitter.com/davidfowl/status/1414248482743853058?ref_src=twsrc%5Etfw&ref=daveabrock.com">July 11, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>This <code>Results</code> class looks nice, especially if you aren't a fan of attributes for MVC controllers. I'm interested to see if it can be extended further, and <a href="https://twitter.com/davidfowl/status/1414313120890114050?ref=daveabrock.com">the team is looking into it</a>.</p><p>If you're looking to extend model binding by using a single request object, you'll have to wait as it won't make it into .NET 6 (<a href="https://twitter.com/davidfowl/status/1414290347992096773?ref=daveabrock.com">but maybe .NET 7</a>). You can bind directly from the JSON object, but manually dealing with route and query parameters might get a tad unwieldy.</p><hr><p>If you're looking to help with some open-source, David Pine could use some help. David has a project called the <a href="https://github.com/IEvangelist/azure-cosmos-dotnet-repository?ref=daveabrock.com">Azure Cosmos DB Repository .NET SDK</a>, which allows you to use the repository pattern to work with your Cosmos DB instances. It really helps to simplify working with CRUD behavior in Cosmos, especially if you're familiar with the <code><code>IRepository</code>&lt;T&gt;</code> interface. I find it quite nice, and use it for one of my projects (<a href="https://www.daveabrock.com/2020/12/13/blast-off-blazor-cosmos/">and have written about it as well</a>).</p><p>David is working on a Blazor book for O'Reilly—if you've ever written a book or know someone who has, you won't be surprised to hear he'll need some help with the project. If you're interested in helping out, <a href="https://twitter.com/davidpine7/status/1413140213992345610?ref=daveabrock.com">let him know</a>.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/07/09/end-to-end-ui-testing-using-specflow/?ref=daveabrock.com" rel="nofollow">works on end-to-end UI testing using SpecFlow</a>.</li><li>Steve Gordon writes about the StringBuilder in <a href="https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-1?ref=daveabrock.com">two</a> <a href="https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-2?ref=daveabrock.com">posts</a>. </li><li>Sam Walpole <a href="https://hackernoon.com/higher-order-functions-in-c-a-practical-example-ae6t35t7?source=rss" rel="nofollow">writes about higher-order functions in C#</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/exploring-automation-properties-in-xamarin-forms/?ref=daveabrock.com" rel="nofollow">explores automation properties</a> in Xamarin.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Colin Eberhardt <a href="https://blog.scottlogic.com/2021/07/03/github-copilot-first-thoughts.html?ref=daveabrock.com" rel="nofollow">writes about GitHub Copilot</a>, and <a href="https://www.infoq.com/news/2021/07/github-copilot-pair-programmming/?ref=daveabrock.com">so does Renato Losio</a>.</li><li>Matthew MacDonald asks: <a href="https://medium.com/young-coder/is-windows-11-a-better-os-for-developers-ea268aa510a4?ref=daveabrock.com" rel="nofollow">is Windows 11 a Better OS for developers?</a></li><li>In community standups, we have Machine Learning <a href="https://www.youtube.com/watch?v=oWsrWWCpseA&ref=daveabrock.com">talking about model explainability</a> and Languages &amp; Runtime <a href="https://www.youtube.com/watch?v=J0LTqwTojlA&ref=daveabrock.com">talks about what's coming up with the next .NET 6 previews</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Matthew Jones <a href="https://exceptionnotfound.net/solitaire-in-blazor-part-5-double-click-shortcut-and-autocomplete/?ref=daveabrock.com" rel="nofollow">continues building a Solitaire game in Blazor</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/adding-authentication-to-a-blazor-server-app-using-auth0/?ref=daveabrock.com" rel="nofollow">adds authentication to a Blazor Server app using Auth0</a>.</li><li>Vladimir Pecanac <a href="https://code-maze.com/ten-things-avoid-aspnetcore-controllers/?ref=daveabrock.com" rel="nofollow">writes about things to avoid in your ASP.NET Core controllers</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/decrypt-secrets-into-aspnet-core-mvc-action-arguments-using-action-filters?ref=daveabrock.com" rel="nofollow">decrypts secrets into ASP.NET Core MVC action arguments using action filters</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Jason Bock <a href="https://medium.com/rocket-mortgage-technology-blog/anagrams-and-prime-numbers-20ba440704b0?ref=daveabrock.com" rel="nofollow">works on anagrams and prime numbers in .NET</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/i-am-a-windows-app-developer/?ref=daveabrock.com" rel="nofollow">writes about what it means to be a Windows app developer</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/top-10-new-net-6-0-api/?ref=daveabrock.com" rel="nofollow">writes about some .NET 6 API updates and improvements</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/azure/how-to-create-a-discord-bot-using-the-dotnet-worker-template-and-host-it-on-azure-container-instances?ref=daveabrock.com">creates a Discord Bot using the .NET worker template</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-07-05-graphql-on-azure-part-7-server-side-authentication/?ref=daveabrock.com" rel="nofollow">continues his series of GraphQL on Azure</a>, <a href="https://www.aaron-powell.com/posts/2021-07-09-creating-static-web-apps-with-fsharp-and-fable/?ref=daveabrock.com" rel="nofollow">creates Azure Static Web Apps with F# and Fable</a>, and also <a href="https://www.aaron-powell.com/posts/2021-07-09-controlling-serialisation-of-cosmosdb-bindings-for-azure-functions/?ref=daveabrock.com" rel="nofollow">controls the serialization of CosmosDB bindings for Azure Functions</a>.</li><li>Mark Heath <a href="https://markheath.net/post/durable-functions-di?ref=daveabrock.com" rel="nofollow">writes about dependency injection in Azure Durable Functions</a>.</li><li>Yohan Lasorsa <a href="http://azpodcast.azurewebsites.net/post/Episode-384-Safe-Deployment-Practices?ref=daveabrock.com" rel="nofollow">builds a shopping app with Azure Static Web Apps</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Davide Bellone <a href="https://www.code4it.dev/csharptips/string-isnullorempty-isnullorwhitespace?ref=daveabrock.com" rel="nofollow">compares String.IsNullOrEmpty and String.IsNullOrWhiteSpace</a>.</li><li>Ken Bonny <a href="https://kenbonny.net/rediscovering-implicit-casting-1?ref=daveabrock.com" rel="nofollow">rediscovers implicit casting in C#</a>.</li><li>Nikola M. Zivkovic <a href="https://rubikscode.net/2021/07/05/c-10-top-5-new-features-in-the-upcoming-c-version/?ref=daveabrock.com" rel="nofollow">writes about upcoming C# 10 features</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-9-New-Features-Adding-foreach-Support-To-Any-Type?ref=daveabrock.com" rel="nofollow">writes about C# 9 foreach support</a>.</li><li>Sanjay Modi <a href="https://procodeguide.com/design/solid-principles-with-csharp-net-core/?ref=daveabrock.com" rel="nofollow">writes about SOLID principles in C#</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Mark Downie <a href="https://www.poppastring.com/blog/using-visual-studio-to-search-objects-in-a-memory-dump?ref=daveabrock.com" rel="nofollow">uses Visual Studio to search objects in a memory dump</a>.</li><li>Raymond Chen asks: <a href="https://devblogs.microsoft.com/oldnewthing/20210706-00/?p=105406&ref=daveabrock.com" rel="nofollow">what happens if I use a squash instead of a true merge?</a></li><li>Joe Guadagno <a href="https://www.josephguadagno.net/2021/07/05/testing-web-apis-or-services-with-jetbrains-rider?ref=daveabrock.com" rel="nofollow">tests Web APIs or services with JetBrains Rider</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/adding-predictive-intellisense-to-my-windows-terminal-powershell-prompt-with-psreadline?ref=daveabrock.com" rel="nofollow">adds predictive IntelliSense to Windows Terminal</a>.</li><li>Alex Russell <a href="https://infrequently.org/2021/07/worktrees-step-by-step/?ref=daveabrock.com" rel="nofollow">writes about Git worktrees</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/uno-weathertwentyone/?ref=daveabrock.com" rel="nofollow">converts an app from .NET MAUI to Uno</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Sarah Drasner <a href="https://css-tricks.com/good-meetings/?ref=daveabrock.com" rel="nofollow">writes about running good meetings</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/mocking-101-first-principles-building-mock-objects?ref=daveabrock.com" rel="nofollow">writes about best practices when mocking objects</a>.</li><li>Sean Killeen <a href="https://seankilleen.com/2021/07/custom-comparers-in-nunit/?ref=daveabrock.com" rel="nofollow">uses custom comparers in NUnit</a>.</li><li>The Overflow writes about <a href="https://stackoverflow.blog/2021/07/07/the-unexpected-benefits-of-mentoring-others/?ref=daveabrock.com" rel="nofollow">the unexpected benefits of mentoring others</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/clean-architecture-example-breakdown/?ref=daveabrock.com" rel="nofollow">talks through a Clean Code architecture example</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The Coding Blocks Podcast <a href="https://www.codingblocks.net/podcast/designing-data-intensive-applications-leaderless-replication/?ref=daveabrock.com" rel="nofollow">continues talking about the DDIA book</a>.</li><li>The .NET Rocks Podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1747&ref=daveabrock.com" rel="nofollow">talks to Jeff Richter about Azure APIs</a>.</li><li>Richard Lander <a href="http://azuredevopspodcast.clear-measure.com/richard-lander-on-the-new-net-platform-episode-148?ref=daveabrock.com" rel="nofollow">talks to the Azure DevOps Podcast</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Shawn Wildermuth <a href="https://wildermuth.com/2021/07/05/Coding-Shorts-Dependency-Injection-Explained?ref=daveabrock.com" rel="nofollow">explains dependency injection</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Diagnosing-thread-pool-exhaustion-issues-in-NET-Core-apps?ref=daveabrock.com" rel="nofollow">diagnoses thread pool exhaustion issues in .NET Core apps</a>, <a href="https://www.youtube.com/watch?v=wBP8k1ZuRmQ&ref=daveabrock.com">discusses Azure Functions with F#</a>, and also <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Null-Coalescing-Assignment?ref=daveabrock.com" rel="nofollow">talks about the null-coalescing assignment operator in C#</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #56: Keeping it short this week ]]></title>
        <description><![CDATA[ It&#39;s a short week this week, but I wanted to send you some links. ]]></description>
        <link>https://www.daveabrock.com/2021/07/04/dotnet-stacks-56/</link>
        <guid isPermaLink="false">60d90ac6d835a2003ea8b035</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 04 Jul 2021 09:17:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/06/THE-.NET-STACKS-3.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, released on June 28, 2021. To get the issues right away, subscribe at </em><a href="https://dotnetstacks.com/?ref=daveabrock.com"><em>dotnetstacks.com</em></a><em> or the bottom of this post.</em></p><p>Happy Monday! Again. I should really come up with a better opening line. Anyway, it's been a pretty crazy week and I haven't had time to dive deep into any topics this week. As such, I'll just be providing you with the links this week. </p><p>Also, thanks to the Independence Day holiday in the US, I'll be taking next week off and will be back with a full issue on July 12. See you then! </p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/partial-range-http-requests-with-aspnet-core?ref=daveabrock.com" rel="nofollow">writes about HTTP range requests and partial responses with ASP.NET Core</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/upload-and-resize-an-image-natively-with-asp-net-core/?ref=daveabrock.com" rel="nofollow">uploads and resizes an image natively with ASP.NET Core</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/exploring-keyboard-accessibility-in-xamarin-forms/?ref=daveabrock.com" rel="nofollow">explores keyboard accessibility in Xamarin</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>The ML.NET team <a href="https://devblogs.microsoft.com/dotnet/ml-net-june-updates-model-builder?ref=daveabrock.com" rel="nofollow">provides their June update</a>.</li><li>Microsoft is <a href="https://techcommunity.microsoft.com/t5/educator-developer-blog/join-us-for-a-live-event-on-azure-static-web-apps-30th-june-2021/ba-p/2467058?ref=daveabrock.com" rel="nofollow">hosting a live Azure Static Web Apps event on Wednesday</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>The NuGet Package Explorer <a href="https://platform.uno/blog/nuget-package-explorer-is-now-a-web-app-powered-by-uno-platform/?ref=daveabrock.com" rel="nofollow">is now on the web, thanks to Uno</a>.</li><li>Stack Overflow <a href="https://stackoverflow.blog/2021/06/23/collectives-stack-overflow/?ref=daveabrock.com" rel="nofollow">introduces a Communities platform</a>.</li><li>Mario Rodriguez <a href="https://github.blog/2021-06-23-introducing-new-github-issues/?ref=daveabrock.com" rel="nofollow">talks about the new GitHub Issues</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=vWzPYYoW0kM&ref=daveabrock.com">talks to Isaac Levin about GitHub Codespaces</a>.</li><li>In community standups, <a href="https://www.youtube.com/watch?v=OTpxQFXxKPs&ref=daveabrock.com">ASP.NET talks architecture</a>, Desktop <a href="https://www.youtube.com/watch?v=gTWsfln6wPY&ref=daveabrock.com">covers all the updates</a>, and <a href="https://www.youtube.com/watch?v=euXpDYGgkGM&ref=daveabrock.com">Machine Learning discusses AutoML</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Sam Basu <a href="https://www.telerik.com/blogs/blazor-wpf?ref=daveabrock.com" rel="nofollow">writes about Blazor on WPF</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/solitaire-in-blazor-part-3-drawing-discarding-and-the-stacks/?ref=daveabrock.com" rel="nofollow">continues building Solitaire in Blazor</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-azure-active-directory-to-secure-a-blazor-webassembly-standalone-app/?ref=daveabrock.com" rel="nofollow">uses Azure AD to secure a Blazor WebAssembly standalone app</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Jun/20/Locked-Files-When-Publishing-NET-Core-Apps-to-IIS-with-WebDeploy?ref=daveabrock.com" rel="nofollow">works with locked files when publishing .NET Core apps to IIS with WebDeploy</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/06/21/maui-preview-5.aspx?ref=daveabrock.com" rel="nofollow">provides an update on .NET MAUI Preview 5</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/winui-visual-studio-2022/?ref=daveabrock.com" rel="nofollow">writes about Project Reunion and Visual Studio 2022</a>.</li><li>Anirudh Agnihotry <a href="https://devblogs.microsoft.com/dotnet/package-validation?ref=daveabrock.com" rel="nofollow">writes about package validation</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-june-2021?ref=daveabrock.com" rel="nofollow">provides their monthly update</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/193985-A/the-cost-of-the-cloud?Key=adc40a40-adeb-4640-a08c-c7a842fe490f&ref=daveabrock.com" rel="nofollow">writes about the cost of the cloud</a>.</li><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-06-24-blazor-typescript-and-static-web-apps/?ref=daveabrock.com" rel="nofollow">writes about Blazor, TypeScript, and Azure Static Web Apps</a>.</li><li>Michael Washington <a href="https://blazorhelpwebsite.com/ViewBlogPost/52?ref=daveabrock.com" rel="nofollow">writes about Blazor Azure Communication Services</a>.</li><li>Yohan Lasorsa <a href="https://dev.to/azure/16-tips-to-master-your-azure-static-web-apps-3cgn?ref=daveabrock.com" rel="nofollow">writes about tips to work with Azure Static Web Apps</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-9-New-Features-More-Pattern-Matching-Features?ref=daveabrock.com" rel="nofollow">writes about C# 9 pattern matching</a>.</li><li>Andrei Fedotov <a href="https://dev.to/andreisfedotov/c-ranges-and-indexes-1nig?ref=daveabrock.com" rel="nofollow">writes about C# ranges and indexes</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/using-ssh-and-localhost-run-to-test-github-webhooks-locally/?ref=daveabrock.com" rel="nofollow">uses SSH and localhost.run to test GitHub webhooks locally</a>.</li><li>Mark Downie <a href="https://www.poppastring.com/blog/debug-analyze-dump-files-in-visual-studio?ref=daveabrock.com" rel="nofollow">debugs and analyzes dump files in Visual Studio</a>.</li><li>Nicholas Blumhardt <a href="https://nblumhardt.com/2021/06/customize-serilog-json-output/?ref=daveabrock.com" rel="nofollow">writes about customized JSON formatting with Serilog</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Davide Bellone <a href="https://www.code4it.dev/cleancodetips/02-principle-of-least-surprise?ref=daveabrock.com" rel="nofollow">offers a clean coding tip</a>.</li><li>The Overflow asks: <a href="https://stackoverflow.blog/2021/06/21/can-innersource-bring-open-source-practices-to-closed-corporate-bureaucracies/?ref=daveabrock.com" rel="nofollow">can InnerSource bring open source practices to closed corporate bureaucracies?</a></li><li>Steve Smith <a href="https://ardalis.com/improving-method-function-clarity/?ref=daveabrock.com" rel="nofollow">talks about improving method and function clarity</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-79-greenfield-and-brownfield-in-net-with-harry-bellamy-part-two/?ref=daveabrock.com" rel="nofollow">continues its conversation with Harry Bellamy</a>.</li><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-201-sustainable-oss-with-rockford-lhotka/?ref=daveabrock.com" rel="nofollow">talks about sustainable OSS with Rockford Lhotka</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/charlie-kindel-on-terminalgui-episode-146?ref=daveabrock.com" rel="nofollow">talks about Terminal.Gui</a>.</li><li>The .NET Rocks Podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1745&ref=daveabrock.com" rel="nofollow">talks to Dan North about SOLID and CUPID</a>.</li><li>The Working Code Podcast <a href="https://www.bennadel.com/blog/4069-working-code-podcast-episode-028-build-vs-buy.htm?ref=daveabrock.com" rel="nofollow">talks about build vs. buy</a>.</li><li>The Web Rush Podcast <a href="https://www.webrush.io/episodes/episode-139-building-the-static-web-apps-cli-with-wassim-chegham?ref=daveabrock.com" rel="nofollow">talks about building the Static Web Apps CLI with Wassim Chegham</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>JetBrains hosts a webinar <a href="https://blog.jetbrains.com/dotnet/2021/06/25/absolute-beginner-s-guide-to-docker-webinar-recording/?ref=daveabrock.com" rel="nofollow">on getting started with Docker</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=2iZdZx7nugI&ref=daveabrock.com" rel="nofollow">work on Playwright Inspector</a>.</li><li>The On .NET Show <a href="https://www.youtube.com/watch?v=gZOwXiOYHHc&ref=daveabrock.com">talks about C# records</a>, <a href="https://www.youtube.com/watch?v=xyOTfCCsD04&ref=daveabrock.com">discusses using declarations</a>, and <a href="https://www.youtube.com/watch?v=EUOimtP78jQ&ref=daveabrock.com">builds reactive UIs with Blazor</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #55: 🆕 Ready or not, here comes .NET 6 Preview 5 ]]></title>
        <description><![CDATA[ .NET 6 Preview 5 has arrived, and so has Visual Studio 2022 Preview 1. ]]></description>
        <link>https://www.daveabrock.com/2021/06/27/dotnet-stacks-55/</link>
        <guid isPermaLink="false">60cdea419caef9003b75e236</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 27 Jun 2021 08:25:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/06/THE-.NET-STACKS-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another busy week! Here's what we have in store this Monday morning:</p><ul><li>One big thing: .NET 6 Preview 5 has arrived</li><li>The little things: Visual Studio 2022 Preview 1 has arrived, dropping support for older frameworks, Markdown tables extension</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-net-6-preview-5-has-arrived">One big thing: .NET 6 Preview 5 has arrived</h2><p>Even though it still seems that we're still recovering from Preview 4 announced around Build, it's about that time: .NET 6 Preview 5 <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com">arrived last Thursday</a>. While Preview 4 brought a lot of developer productivity and experience features like Minimal APIs and Blazor WebAssembly AOT, Preview 5 is a jam-packed release with a lot of work going towards unification in .NET 6.</p><p>A big part of that is <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#net-sdk-optional-workload-improvements">SDK workloads</a>—<a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#cli-install-of-net-6-sdk-optional-workloads">announced in Preview 4</a>— a new .NET SDK feature that enables the .NET team to add support for new application types without increasing the size of the SDK. For example, you may want to include MAUI or Blazor WebAssembly application types as you need them. You can view SDK workloads as a package manager for the .NET SDK—the emphasis on <em>the </em>SDK,<em> </em>as Microsoft's vision of one SDK is coming together.</p><p>On top of that, Preview 5 brings <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#net-sdk-nuget-package-validation">NuGet package validation</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#net-sdk-more-roslyn-analyzers">a lot more Roslyn analyzers</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#libraries-microsoft-extensions">improvements to the <code>Microsoft.Extensions</code> APIs</a>, a <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#libraries-jsonserializer-source-generation">new JSON source generator</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#libraries-websocket-compression">WebSocket compression</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#libraries-support-for-opentelemetry-metrics">OpenTelemetry support</a>, and much more. What about ASP.NET Core? Hot Reload <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-5/?ref=daveabrock.com#net-hot-reload-updates-for-dotnet-watch">is enabled by default</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-5/?ref=daveabrock.com#reduced-blazor-webassembly-download-size-with-runtime-relinking">improvements to Blazor WebAssembly download size with runtime relinking</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-5/?ref=daveabrock.com#faster-get-and-set-for-http-headers">faster gets and sets for HTTP headers</a>, and more. </p><p>With EF Core, Preview 5 <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-5-compiled-models/?ref=daveabrock.com">brings the first iteration of compiled models</a>. Much like Blazor WebAssembly ahead-of-time (AOT) compilation, the compiled models functionality addresses increasing your startup time. As Jeremy Likness notes: "If startup time for your application is important and your EF Core model contains hundreds or thousands of entities, properties, and relationships, this is one release you don’t want to ignore." </p><p>The EF team is reporting 10<em>x</em> performance gains using compiled models. How does this work? When EF creates a context, it creates and compiles delegates to set the table properties. This gives you the ability to query properties right away. Using lazy initialization, EF Core only is accessed when needed. You'll <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-5-compiled-models/?ref=daveabrock.com">want to check out the blog post</a> for an in-depth discussion of all that's involved. While a fast startup time won't get any complaints, keep in mind that global query filters, lazy loading proxies, change tracking proxies, and <code>IModelCacheKeyFactory</code> implementations aren't supported yet.</p><p>If mobile/desktop development is your jam, you'll also <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-5/?ref=daveabrock.com">want to check out MAUI updates for Preview 5</a>.</p><hr><h2 id="the-little-things-visual-studio-2022-preview-1-is-here-dropping-support-for-older-frameworks-markdown-tables-extension">The little things: Visual Studio 2022 Preview 1 is here, dropping support for older frameworks, Markdown tables extension</h2><p>After much fanfare about 64-bit support, Visual Studio 2022 Preview 1 <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/?ref=daveabrock.com">is now here and available for you to try out</a>. By all accounts, it seems to be smooth and snappy—you know, as it should be—and can be installed with earlier versions of Visual Studio. You can <a href="https://docs.microsoft.com/en-us/visualstudio/productinfo/vs-roadmap?ref=daveabrock.com">check out the Visual Studio 2022 roadmap</a> to see what's coming next.</p><p>The 64 bits are getting most of the buzz, but you also may have <a href="https://devblogs.microsoft.com/visualstudio/type-less-code-more-with-intellicode-completions/?ref=daveabrock.com">missed support for IntelliCode completions</a>. These updates complete code for you, sometimes even whole lines of code. Based on your context, it'll predict the next part of code to write, and gives you the option to <code>Tab</code> to accept the changes. Mark Wilson-Thomas mentions this is done by combining a "rich knowledge of your coding context" and also a transformer model that is trained on around half a million public open-source GitHub repositories.</p><p>Here's a quick example of me testing it out:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/06/image-2.png" class="kg-image" alt loading="lazy" width="1392" height="326" srcset="https://www.daveabrock.com/content/images/size/w600/2021/06/image-2.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/06/image-2.png 1000w, https://www.daveabrock.com/content/images/2021/06/image-2.png 1392w" sizes="(min-width: 720px) 720px"></figure><p>In another example, I wrote a function to print out the first name and last name—it suggested I concatenated the strings together. (I would have preferred string interpolation, but I digress.) Then, as I did a <code>WriteLine</code> call, it suggested I use the method I just wrote. </p><hr><p>The .NET team is embarking on an effort <a href="https://github.com/dotnet/announcements/issues/190?ref=daveabrock.com">to drop older framework versions</a>. While dropping frameworks can be a breaking change, building for every framework version increases complexity and size. The team worked around this by harvesting—building for current frameworks but downloading a package's earlier version and harvest binaries for earlier frameworks. This allows you to update without the worry of losing a framework version, but you won't get any fixes or features from these binaries.</p><p>Starting with .NET 6 Preview 5, the .NET team will no longer harvest to ensure support for all assets. This means they are dropping support for frameworks older than .NET Framework 4.6.1, .NET Core 3.1, and .NET Standard 2.0.</p><p>As <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com#libraries-dropping-support-for-older-frameworks">Richard Lander writes</a>:</p><blockquote>If you’re currently referencing an impacted package from an earlier framework, you’ll no longer be able to update the referenced package to a later version. Your choice is to either retarget your project to a later framework version or not updating the referenced package (which is generally not a huge take back because you’re already consuming a frozen binary anyways).</blockquote><hr><p>Here's something I learned this week: there's a <a href="https://twitter.com/DynamicWebPaige/status/1404804509730316302?ref=daveabrock.com">Markdown Tables extension in Visual Studio Code</a>. Who do I talk to about refunding all my time spent tweaking Markdown tables?</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p>It's another busy week with new preview releases for .NET and Visual Studio. </p><h3 id="%F0%9F%94%A5-the-top-5">🔥 The Top 5</h3><ul><li>.NET 6 Preview 5 is out: Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/?ref=daveabrock.com" rel="nofollow">announces it</a>, Daniel Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-5/?ref=daveabrock.com" rel="nofollow">writes about ASP.NET Core updates</a>, Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-5-compiled-models/?ref=daveabrock.com" rel="nofollow">covers EF Core</a>, and David Ortinau <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-5/?ref=daveabrock.com" rel="nofollow">covers .NET MAUI</a>.</li><li>Visual Studio 2022 Preview 1 <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/?ref=daveabrock.com" rel="nofollow">is now available</a>, and <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-16-11-preview-2/?ref=daveabrock.com">so is 2019 16.11 Preview 2</a>.</li><li>David Pine <a href="https://dev.to/dotnet/why-build-single-page-apps-in-blazor-103m?ref=daveabrock.com" rel="nofollow">writes about building SPAs with Blazor</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/remote-repositories-a-better-experience-for-github-in-vs-code-9edcc7d20a41?ref=daveabrock.com" rel="nofollow">writes about the new VS Code Remote Repositories extension</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/exploring-drag-and-drop-in-xamarin-forms/?ref=daveabrock.com" rel="nofollow">explores drag-and-drop in Xamarin</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/dotnet-repl?ref=daveabrock.com" rel="nofollow">introduces dotnet repl</a>.</li><li>Mika Dumont <a href="https://devblogs.microsoft.com/visualstudio/learn-whats-new-in-net-productivity?ref=daveabrock.com" rel="nofollow">shares what's new with Roslyn</a>.</li><li>The Uno Platform <a href="https://platform.uno/blog/uno-platform-3-8-new-winui-calendar-grid-controls-2x-performance-new-linux-scenario-and-more/?ref=daveabrock.com" rel="nofollow">introduces the 3.8 release</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>The next .NET Conf, on July 29, <a href="https://focus.dotnetconf.net/?ref=daveabrock.com" rel="nofollow">will have an F# focus</a>.</li><li>Jon Skeet <a href="https://codeblog.jonskeet.uk/2021/06/11/new-book-software-mistakes-and-tradeoffs/?ref=daveabrock.com" rel="nofollow">has a new book</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=TSvsj-nQxik&ref=daveabrock.com">talks to Konrad Kokosa</a>.</li><li>For community standups: Tooling <a href="https://www.youtube.com/watch?v=s177EoV2-jY&ref=daveabrock.com">previews Hot Reload for WinForms and WPF</a>, Entity Framework <a href="https://www.youtube.com/watch?v=nEqH_XfCfho&ref=daveabrock.com">discusses Azure Cosmos DB and EF Core</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=Hz8i2HPSPts&ref=daveabrock.com">builds Teams apps using Blazor</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Mahesh Sabnis <a href="https://www.dotnetcurry.com/aspnet-core/blazor-state-management?ref=daveabrock.com" rel="nofollow">works with state management in Blazor apps</a>.</li><li>Jignesh Trivedi <a href="https://www.c-sharpcorner.com/article/event-handling-in-blazor/?ref=daveabrock.com" rel="nofollow">works on event handling in Blazor</a>.</li><li>Dave Brock <a href="https://www.daveabrock.com/2021/06/15/upgrade-blazor-static-app-net-5-net-6/" rel="nofollow">updates a Blazor WebAssembly app from .NET 5 to .NET 6</a> and <a href="https://www.telerik.com/blogs/your-guide-rest-api-versioning-aspnet-core?ref=daveabrock.com" rel="nofollow">writes about REST API versioning in ASP.NET Core</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-dapper-with-asp-net-core-web-api/?ref=daveabrock.com" rel="nofollow">uses Dapper with ASP.NET Core Web API</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/solitaire-in-blazor-part-2-the-csharp-classes/?ref=daveabrock.com" rel="nofollow">continues his Solitaire in Blazor series</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Ben Watson <a href="https://devblogs.microsoft.com/dotnet/migration-of-bings-workflow-engine-to-net-5?ref=daveabrock.com" rel="nofollow">writes about Bing migrating their Workflow Engine to .NET 5</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/06/15/project-reunion-8-rc.aspx?ref=daveabrock.com" rel="nofollow">writes about Project Reunion updates</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-networking/?ref=daveabrock.com" rel="nofollow">mediates a conversation about networking</a> and <a href="https://devblogs.microsoft.com/dotnet/conversation-about-diagnostics?ref=daveabrock.com" rel="nofollow">diagnostics</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/setting-content-for-httpclient-testing-with-json.net-and-system.text.json?ref=daveabrock.com" rel="nofollow">sets content for HttpClient testing with JSON.NET and System.Text.Json</a>.</li><li>Daniel Gomez Jaramillo <a href="https://www.c-sharpcorner.com/article/hot-reload-for-net-developers/?ref=daveabrock.com" rel="nofollow">writes about hot reload for .NET developers</a>.</li><li>Varun Setia <a href="https://www.c-sharpcorner.com/article/new-programming-model-for-handling-json-in-net-6/?ref=daveabrock.com" rel="nofollow">describes a new programming model for handling JSON in .NET 6</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/show-a-name-and-profile-photo-with-dotnet-and-gravatar/?ref=daveabrock.com" rel="nofollow">shows a name and profile photo with .NET and Gravatar</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/how-to-logically-name-embedded-resources-in-csproj/?ref=daveabrock.com" rel="nofollow">logically names embedded resources in a .csproj file</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Jun/15/Running-NET-Core-Apps-on-a-Framework-other-than-Compiled-Version?ref=daveabrock.com" rel="nofollow">runs .NET Core apps on a framework other than a compiled version</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/06/11/azure-functions-net-6.aspx?ref=daveabrock.com" rel="nofollow">writes about .NET 6 support on Azure Functions</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2021/06/11/azure-functions-dotnet-5-query-params-di-bicep/?ref=daveabrock.com" rel="nofollow">works with Azure Functions and .NET 5</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/azure-service-bus-queue-vs-topic?ref=daveabrock.com" rel="nofollow">compares queues and topics in Azure Service Bus</a>.</li><li>Hugo G Fernandez R <a href="https://www.codeproject.com/Articles/5261514/Creating-a-RESTful-API-with-Automatic-Documentatio?ref=daveabrock.com" rel="nofollow">creates a RESTful API with automatic documentation on Azure App Service</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/csharp-pattern-matching-quick-guide-and-examples?ref=daveabrock.com" rel="nofollow">writes about C# pattern matching</a>.</li><li>Niels Rasmussen <a href="https://nietras.com/2021/06/14/csharp-10-record-struct/?ref=daveabrock.com" rel="nofollow">goes deep on record structs in C# 10</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Mitchel Sellers <a href="https://www.mitchelsellers.com/blog/article/dependency-injection-async-and-hangfire-for-simple-background-processing?ref=daveabrock.com" rel="nofollow">works on DI, async, and HangFire for background processing</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/06/14/csharp-scripting.aspx?ref=daveabrock.com" rel="nofollow">writes about C# scripting</a>.</li><li>Mark Wilson-Thomas <a href="https://devblogs.microsoft.com/visualstudio/type-less-code-more-with-intellicode-completions/?ref=daveabrock.com" rel="nofollow">writes about IntelliCode completions in Visual Studio</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Steve Smith <a href="https://ardalis.com/prioritizing-and-microservices/?ref=daveabrock.com" rel="nofollow">writes about prioritizing and microservices</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/real-time-web-by-leveraging-event-driven-architecture/?ref=daveabrock.com" rel="nofollow">talks about leveraging event-driven architecture for the real-time web</a>.</li><li>David Adsit <a href="https://www.pluralsight.com/blog/software-development/tdd-vs-bdd?ref=daveabrock.com" rel="nofollow">compares TDD and BDD</a>.</li><li>Anwar Al Jahwari <a href="https://better-dev.io/interface-segregation-principle/?ref=daveabrock.com" rel="nofollow">writes about the Interface Segregation Principle</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1744&ref=daveabrock.com" rel="nofollow">talks about open source in the enterprise</a>.</li><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-78-greenfield-and-brownfield-in-net-with-harry-bellamy-part-one/?ref=daveabrock.com" rel="nofollow">discusses greenfield and brownfield in .NET with Harry Bellamy</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>On .NET <a href="https://dev.to/dotnet/on-net-episode-clustering-in-orleans-11eh?ref=daveabrock.com" rel="nofollow">discusses clustering in Orleans</a>, <a href="https://channel9.msdn.com/Shows/On-NET/Working-with-Azure-AD-B2C-in-ASPNET?ref=daveabrock.com" rel="nofollow">works with Azure AD B2C in ASP.NET</a>, talks about <a href="https://www.youtube.com/watch?v=9YdxhhgJvrE&ref=daveabrock.com">using Blazor with Tailwind CSS</a>, <a href="https://www.youtube.com/watch?v=gkpxGhJ31ks&ref=daveabrock.com">gets started with Azure Static Web Apps</a>, and <a href="https://www.youtube.com/watch?v=ZigtOlZ-bV0&ref=daveabrock.com">talks about the null coalescing operator in C#</a>.</li><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Async-Debugging-Part-2?ref=daveabrock.com" rel="nofollow">continues a discussion on async debugging</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ 5 Development Best Practices That Will Help You Craft Better Tests ]]></title>
        <description><![CDATA[ Automating tests is hard. You can make it manageable by using these tips, techniques, and tools to help you speed up the process. ]]></description>
        <link>https://www.daveabrock.com/2021/06/23/development-best-practices-better-tests/</link>
        <guid isPermaLink="false">60a2ae294dc2e1003bc1b6a8</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 23 Jun 2021 10:04:10 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHRlc3R8ZW58MHx8fHwxNjI0NDYwMzM3&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post originally appeared on the <a href="https://www.telerik.com/blogs/5-development-best-practices-help-craft-better-tests?ref=daveabrock.com">Telerik Developer Blog</a>.</em></p><p>Our industry's advancements in agile methodologies, DevOps, and even cloud engineering have brought a key capability to focus on: shared responsibility. </p><p>If you've been a developer for a while, you might remember throwing operation problems to an Ops team, testing to a QA team, and so on. These days, developing applications isn't just about developing applications. When developers are invested in the entire lifecycle of the application process, it results in a more invested and productive team. </p><p>This doesn't come without drawbacks, of course. While having specialists in those areas will always have value—and seeing these specialists on the development team can be tremendously helpful—developers can feel overwhelmed with all they need to take on. I often see this when it comes to automated testing. As developers, we know we need to test our code, but how far should we take it? After a certain point, isn't the crafting of automated tests the responsibility of QA?</p><p>The answer: it's everyone's responsibility and not something you should throw over the wall to your QA department (if you're lucky enough to have one). This post attempts to cut through the noise and showcase best practices that will help you craft better automated tests. </p><h2 id="defining-automated-testing">Defining Automated Testing</h2><p>When I talk about automated tests, I'm referring to a process that uses tools to execute predefined tests <a href="https://www.telerik.com/blogs/overview-of-automated-testing-for-developers?ref=daveabrock.com">based on predetermined events</a>. This isn't meant to be an article focused on differentiating concepts like unit testing or integration testing—if they are scheduled or triggered based on events (like checking in code to the main branch), these are both automated tests.</p><p>As a result of having an automated testing pipeline, you can confidently ship low-risk releases and ship better products with higher quality. Of course, automated testing isn't a magic wand—but done appropriately, it can give your team confidence that you're shipping a quality product. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/06/image-3.png" class="kg-image" alt loading="lazy" width="1885" height="1037" srcset="https://www.daveabrock.com/content/images/size/w600/2021/06/image-3.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/06/image-3.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/06/image-3.png 1600w, https://www.daveabrock.com/content/images/2021/06/image-3.png 1885w" sizes="(min-width: 720px) 720px"></figure><h2 id="decide-which-tests-to-automate">Decide Which Tests to Automate</h2><p>It isn't practical to say that you want to automate <em>all </em>your test cases. In a perfect world, would you want to? Sure. This isn't a perfect world: you have lots to get done, and you can't expect to test everything. Also, many of your tests need human judgment and intervention. </p><p>How often do you need to repeat your test? Is it something that is rarely encountered and only done a few times? A manual test should be fine. However, if tests need to be run frequently, it's a good candidate for an automated test.</p><p>Here are some more scenarios to help you identify good candidates for automated tests:</p><ul><li>When tested manually, it is hard to get right? Do folks spend a lot of time setting up conditions to test manually?</li><li>Does it cause human error?</li><li>Do tests need to be integrated across multiple builds?</li><li>Do you require large data sets for performing the same actions on your tests?</li><li>Does the test cover frequent, high-risk, and hot code paths in your application?</li></ul><h2 id="test-early-often-and-frequently">Test Early, Often, and Frequently</h2><p>Your test strategy should be an early consideration and not an afterthought. If you're on a three-week sprint cycle and you're repeatedly rushing to write, fix, or update your tests on the third week, you're headed for trouble. When this happens, teams often rush to get the tests working—you'll see tests filled with inadequate test conditions and messy workarounds.</p><p>When you make automated testing an important consideration, you can run tests frequently and detect issues as they arise. In the long run, this will save a lot of time—plus, you'd much rather fix issues early than have an angry customer file a production issue because your team didn't give automated testing the attention it deserved.</p><h2 id="consistently-evaluate-valid-and-accurate-results">Consistently Evaluate Valid and Accurate Results</h2><p>To that end, your team should always be comfortable knowing your tests are consistent, accurate, and repeatable. Does the team check-in code without ensuring that previous testing is still accurate?  Saying all the tests pass is <em>not </em>the same as saying that the tests are accurate. When it comes to unit testing, in many automated CI/CD systems, you can integrate build checks to ensure code coverage does not consistently drop whenever new features enter the codebase.</p><p>If tests are glitchy or unstable, take the time to understand why and not repeatedly manually restart runs because sometimes it works and sometimes it doesn't. If needed, remove these tests until you can resolve these issues.</p><h2 id="ensure-quality-test-result-reporting">Ensure Quality Test Result Reporting</h2><p>What good is an automated test suite if you don't have an easy way to detect, discover, and resolve issues? When a test fails, development teams should be alerted immediately. While the team might not know how to fix it right away, they should know where to look, thanks to having clearly named tests and error messages, robust tools, and a solid reporting infrastructure. Developers should then spend their time resolving issues and not going in circles to understand what the issue is and where it lies.</p><h2 id="pick-the-right-tool">Pick The Right Tool</h2><p>Automated testing can become more manageable with the right tools. So I hope you're sitting down for this: I recommend <a href="https://www.telerik.com/teststudio/test-automation-solutions-for-the-entire-team?ref=daveabrock.com">Telerik Test Studio</a>. With Telerik Test Studio, everyone can and drive value from your testing footprint: whether it's developers, QA, or even your pointy-haired bosses. </p><p>Developers can use the Test Studio Dev Edition to automate your complex .NET applications right from Visual Studio. QA engineers can use Test Studio Standalone to facilitate developing functional UI testing. Finally, when you're done telling your managers, "I'm not slacking, I'm compiling," you can point them to the web-based Executive Dashboard for monitoring test results and building reports. </p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #54: 🎀 Putting a bow on .NET 6 date and time updates ]]></title>
        <description><![CDATA[ This week, we finish talking about date and time improvements that are coming with the .NET 6 release. ]]></description>
        <link>https://www.daveabrock.com/2021/06/20/dotnet-stacks-54/</link>
        <guid isPermaLink="false">60c6395f9caef9003b75dff2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 20 Jun 2021 10:30:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/06/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, released on June 14, 2021. To get the issues right away, subscribe at </em><a href="https://dotnetstacks.com/?ref=daveabrock.com"><em>dotnetstacks.com</em></a><em> or the bottom of this post.</em></p><p>Happy Monday! Here's what's going on this week:</p><ul><li><strong>The big thing</strong>: Putting a bow on .NET 6 date and time updates</li><li><strong>The little things</strong>: Have I Been Pwned project updates, VS Code remote repositories extension, App Service support on .NET 6, Azure Functions updates</li><li>Last week in the .NET world</li></ul><hr><h2 id="the-big-thing-putting-a-bow-on-net-6-date-and-time-updates">The big thing: Putting a bow on .NET 6 date and time updates</h2><p>In a previous issue, we briefly spent some time exploring the new date and time APIs in .NET 6. (Despite feedback of the cringy title, I stand behind <em><a href="https://www.daveabrock.com/2021/04/03/dotnet-stacks-43/">DateTime might be seeing other people</a></em>.) In these posts, I passed along the information from various GitHub issues. This week, it was nice to see Matt Johnson-Pint officially <a href="https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/?ref=daveabrock.com">write about it in detail on the .NET Blog</a>.</p><p>Here's the gist: the .NET team is rolling out <em>new </em><code>DateOnly</code> and <code>TimeOnly</code> types for .NET 6. </p><p>The <code>DateOnly</code> type, if you can believe it, only supports a date—like a year or a month. You might want to use this when you don't need an associated time, like birthdays and anniversaries. With <code>DateOnly</code> Microsoft promises better type safety when you only want dates, serialization improvements, and simplicity when interacting with databases. <code>DateOnly</code> ships with a robust constructor but no deconstructor.</p><p>As for <code>TimeOnly</code>, you'd use it only to represent a time of day. Potential use cases are alarm clock times, when a business is open, or recurring appointment times. Why not <code>TimeSpan</code>? Here, <code>TimeOnly</code> is intended for a time of day and not elapsed time. Again, you'll gain type safety and more accuracy when calculating ranges.</p><p>There's a lot of chatter in the community asking: why not use Noda Time instead? From the post:</p><blockquote>Noda Time is a great example of a high-quality, community developed .NET open source library ... However, we didn’t feel that implementing a Noda-like API in .NET itself was warranted. After careful evaluation, it was decided that it would be better to <em>augment</em> the existing types to fill in the gaps rather than to overhaul and replace them. After all, there are many .NET applications built using the existing <code>DateTime</code>, <code>DateTimeOffset</code>, <code>TimeSpan</code>, and <code>TimeZoneInfo</code> types. The <code>DateOnly</code> and <code>TimeOnly</code> types should feel natural to use along side them.</blockquote><p>As an FYI, the new structs aren't supported in Entity Framework Core 6 yet, but <a href="https://github.com/dotnet/runtime/issues/49036?ref=daveabrock.com#issuecomment-806444260">you can check out this comment</a> to find a relevant tracking issue. You'll want to check out the post—in addition to the new <code>DateOnly</code> and <code>TimeOnly</code> structs, the .NET team is rolling out time zone enhancements as well.</p><p>These changes aren't replacing any <code>DateTime</code> APIs, just augmenting them. So when it comes time for you to switch to .NET 6, do what works for you. </p><hr><h2 id="the-little-things-have-i-been-pwned-project-updates-vs-code-remote-repositories-extension-azure-functions-updates-app-service-support-on-net-6">The little things: Have I Been Pwned project updates, VS Code remote repositories extension, Azure Functions updates, App Service support on .NET 6</h2><p>This week, we'll talk about Have I Been Pwned, a new Visual Studio Code extension, and updates on running Azure Functions and Azure App Service updates on .NET 6.</p><h3 id="have-i-been-pwned-project-updates">Have I Been Pwned project updates</h3><p>You've likely heard of Troy Hunt's <a href="https://haveibeenpwned.com/?ref=daveabrock.com">Have I Been Pwned project</a>. At the risk of oversimplifying all that Troy does, you can use it to check if your personal data has been compromised by data breaches. With the help of Cloudflare and Azure Functions, he's been able to operate <a href="https://www.troyhunt.com/serverless-to-the-max-doing-big-things-for-small-dollars-with-cloudflare-workers-and-azure-functions/?ref=daveabrock.com">at a tremendous scale with minimum cost</a>. That site is now getting <a href="https://twitter.com/troyhunt/status/1397727343167250433?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1397727343167250433%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fwww.troyhunt.com%2Fpwned-passwords-open-source-in-the-dot-net-foundation-and-working-with-the-fbi%2F&ref=daveabrock.com">around 1 billion requests a month</a>.</p><p>Last August, Troy announced <a href="https://www.troyhunt.com/im-open-sourcing-the-have-i-been-pwned-code-base/?ref=daveabrock.com">his plans to take HIBP to open source</a>. Recently, Troy wrote that the Pwned Passwords component <a href="https://www.troyhunt.com/pwned-passwords-open-source-in-the-dot-net-foundation-and-working-with-the-fbi/?ref=daveabrock.com">is now a .NET Foundation project</a>.  You can check out the code <a href="https://github.com/HaveIBeenPwned/?ref=daveabrock.com">at the HaveIBeenPwned organization on GitHub</a>. As a .NET developer, it's a nice way to look at the code and how it all works, especially when it comes to getting hashes and anonymizing requests.</p><h3 id="vs-code-remote-repositories-extension">VS Code remote repositories extension</h3><p>In this space last week, <a href="https://www.daveabrock.com/2021/06/13/dotnet-stacks-53/">we mentioned</a> a new VS Code extension for Project Tye. Visual Studio Code is at it again with <a href="https://code.visualstudio.com/blogs/2021/06/10/remote-repositories?WT.mc_id=devcloud-00000-cxa&ref=daveabrock.com">a new Remote Repositories extension</a>. With this extension, you can browse, search, edit, and commit to any remote GitHub repository without a clone. This extension will support Azure DevOps soon as well. (GitHub is the long-term vision, yet Microsoft is consistently releasing these new capabilities to Azure DevOps. For this and other reasons, I'm pretty sure Azure DevOps will outlive <em>me</em>.) </p><p>Personally, looking at GitHub repos is good for my learning—both for what to do and what not to do—and there should be a middle ground between browsing g<em>ithub.com</em> and cloning a big repository to my machine. This should help. </p><h3 id="azure-functions-updates">Azure Functions updates</h3><p>Last week, Azure Functions PM Anthony Chu wrote about recent Azure Functions updates. (I'll be interviewing him soon here, so hit me up if you have any other questions.) We've written about some of what he mentioned, but not everything—here's the latest.</p><ul><li><strong>Visual Studio support for .NET 5.0 isolated function apps</strong>: Released in May, Visual Studio 2019 16.10 includes full support for .NET 5.0 isolated process Azure Functions apps. You can <a href="https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-developer-howtos?tabs=browser&pivots=development-environment-vs&ref=daveabrock.com">check out the tutorial</a>.</li><li><strong>You can run .NET 6 on Azure Functions</strong>: To do this, you'll need Azure Functions V4—right now, it's limited to a preview release of Azure Functions Core Tools V4. Check out the post, as there are a few caveats to keep in mind. It's early, and there's no official support yet. Microsoft <a href="https://aka.ms/functions-dotnet6earlypreview-wiki?ref=daveabrock.com">has published a tutorial</a> on writing .NET 6 apps on Azure Functions.</li></ul><h3 id="azure-app-service-support-on-net-6">Azure App Service support on .NET 6</h3><p>In somewhat related Azure development news, <a href="https://azure.github.io/AppService/2021/06/09/Dot-Net-6-Preview-on-App-Service.html?ref=daveabrock.com">you can use .NET 6 Preview bits on Azure App Service</a>—in either Windows or Linux workloads. You can do this through the Azure App Service <a href="https://github.com/Azure/app-service-linux-docs/blob/master/Runtime_Support/early_access.md?ref=daveabrock.com">Early Access Runtime feature</a>. This feature allows you to get the latest version of SDKs for various languages. With Early Access Runtime, you can get access without waiting for a release cycle. </p><p>Microsoft is boasting that it's the first time a pre-release stack is publicly available on App Service before the GA release.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p>We've got another busy week with some great content from the developer community.</p><h3 id="%F0%9F%94%A5-the-top-5">🔥 The Top 5</h3><ul><li>Matt Johnson-Pint <a href="https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6?ref=daveabrock.com" rel="nofollow">writes about Date, Time, and Time Zone Enhancements in .NET 6</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/06/07/blazor-component-communication-state-handling/?ref=daveabrock.com" rel="nofollow">works on Blazor component communication and state handling</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/simple-way-to-use-maps-with-xamarin-essentials/?ref=daveabrock.com" rel="nofollow">uses Maps with Xamarin Essentials</a>.</li><li>Microsoft announces <a href="https://code.visualstudio.com/blogs/2021/06/10/remote-repositories?ref=daveabrock.com" rel="nofollow">the new Remote Repositories extension for Visual Studio Code</a>.</li><li>Joseph Guadagno <a href="https://www.telerik.com/blogs/migrate-aspnet-core-mvc-aspnet-framework-mvc?ref=daveabrock.com" rel="nofollow">migrates to ASP.NET Core MVC from ASP.NET Framework MVC</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>For community standups: ASP.NET <a href="https://www.youtube.com/watch?v=8xLw-f1iFLw&ref=daveabrock.com">talks about Blazor updates</a>, and Machine Learning <a href="https://www.youtube.com/watch?v=cLtOQuaqtoQ&ref=daveabrock.com">holds office hours</a>.</li><li>The .NET Docs Show talks to Niels Swimberghe about <a href="https://www.youtube.com/watch?v=e8DX7HdSmkU&ref=daveabrock.com">making calls with Twilio and Blazor WebAssembly</a>.</li><li>Troy Hunt <a href="https://www.troyhunt.com/expanding-the-have-i-been-pwned-volunteer-community/?ref=daveabrock.com" rel="nofollow">expands the Have I Been Pwned volunteer community</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>The Code Maze blog <a href="https://code-maze.com/hangfire-with-asp-net-core/?ref=daveabrock.com" rel="nofollow">uses Hangfire with ASP.NET Core</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/solitaire-in-blazor-part-1-overview/?ref=daveabrock.com" rel="nofollow">starts developing a solitaire game in Blazor</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/extending-httpclient-testing-with-templating?ref=daveabrock.com" rel="nofollow">extends HttpClient testing with templating</a>.</li><li>Bruno Sonnino <a href="https://blogs.msmvps.com/bsonnino/2021/06/05/lightweight-web-api-int-asp-net-with-featherhttp/?ref=daveabrock.com" rel="nofollow">explores Minimal APIs in ASP.NET Core</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/building-aspnet-web-api/?ref=daveabrock.com" rel="nofollow">builds ASP.NET CRUD Web APIs</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/06/10/integration-testing-for-asp-net-core-using-ef-core-cosmos-with-xunit-and-azure-devops/?ref=daveabrock.com" rel="nofollow">explores integration testing for ASP.NET Core using EF Core Cosmos with XUnit and Azure DevOps</a>.</li><li>Dave Brock <a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com" rel="nofollow">writes about minimal APIs in .NET 6</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Jonathan Allen <a href="https://www.infoq.com/news/2021/06/Net6-Collections/?ref=daveabrock.com" rel="nofollow">writes about .NET 6 collections improvements</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-containers?ref=daveabrock.com" rel="nofollow">hosts a conversation about containers</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/exploring-dotnet-interactive-notebooks/?ref=daveabrock.com" rel="nofollow">explores .NET interactive notebooks with VS Code</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/in-the-jungle-of-net-obfuscator-tools/?ref=daveabrock.com" rel="nofollow">recaps .NET obfuscator tools</a>.</li><li>John Miller <a href="https://devblogs.microsoft.com/visualstudio/build-apps-for-microsoft-teams-with-net?ref=daveabrock.com" rel="nofollow">develops apps for Microsoft Teams with .NET</a>.</li><li>Abhijit Jana <a href="https://dailydotnettips.com/command-line-arguments-and-c-9-0-top-level-statement-visual-studio/?ref=daveabrock.com" rel="nofollow">works with command-line arguments and C# 9.0 top-level statements with Visual Studio</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/what-s-new-with-net-on-azure-functions-june-2021/ba-p/2428669?ref=daveabrock.com" rel="nofollow">writes about what's new with .NET on Azure Functions</a>.</li><li>Chris Noring <a href="https://dev.to/azure/azure-static-web-apps-cli-building-apps-locally-3968?ref=daveabrock.com" rel="nofollow">builds apps locally with the Azure Static Web Apps CLI</a>.</li><li>Dominique St-Amand <a href="https://www.domstamand.com/cosmosdb-linux-container-for-your-ci-builds/?ref=daveabrock.com" rel="nofollow">works on a CosmosDB Linux container for your CI builds</a>.</li><li>Shelton Graves <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/event-driven-on-azure-part-2-architecting-event-driven/ba-p/2414007?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com" rel="nofollow">continues his series on working with events in Azure</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Matthew MacDonald <a href="https://medium.com/young-coder/a-closer-look-at-5-new-features-in-c-10-f99738b0158e?ref=daveabrock.com" rel="nofollow">previews 5 new features in C# 10</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/csharptips/how-to-get-item-index-in-foreach?ref=daveabrock.com" rel="nofollow">writes about how to get the index of an item in a foreach loop</a>.</li><li>Ken Bonny <a href="https://kenbonny.net/rediscovering-implicit-casting?ref=daveabrock.com" rel="nofollow">rediscovers implicit casting</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Anant Vernekar <a href="https://www.c-sharpcorner.com/article/integrating-swagger-with-web-api-net-core-using-entity-framework/?ref=daveabrock.com" rel="nofollow">integrates Swagger With ASP.NET Core Using Entity Framework</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/06/08/must-have-jetbrains-rider-plugins-for-asp-net-core-developers/?ref=daveabrock.com" rel="nofollow">writes about JetBrains Rider plugins for ASP.NET Core developers</a> and <a href="https://blog.jetbrains.com/dotnet/2021/06/10/import-settings-from-visual-studio-and-vs-code-to-rider/?ref=daveabrock.com" rel="nofollow">how to import settings from Visual Studio and VS Code to Rider</a>.</li><li>Wael Kdouh <a href="https://waelkdouh.medium.com/automating-deployment-of-azure-logic-app-using-azure-devops-c83d2161097f?ref=daveabrock.com" rel="nofollow">automates deployments of Azure Logic App Using Azure DevOps</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/06/codespaces-gh-cli-git-credentials/?ref=daveabrock.com" rel="nofollow">uses the GitHub CLI and Git with GitHub Codespaces</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/06/10/rider-webassembly-debugging.aspx?ref=daveabrock.com" rel="nofollow">writes about Rider's improvements with Blazor WebAssembly debugging</a>.</li><li>Lauren Del Signore <a href="https://www.grapecity.com/blogs/useful-visual-studio-extensions-blazor?ref=daveabrock.com" rel="nofollow">writes about useful Visual Studio extensions for working with Blazor</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Al Tenhundfeld <a href="https://www.simplethread.com/what-makes-a-good-git-commit/?ref=daveabrock.com" rel="nofollow">asks: what makes a good Git commit?</a></li><li>Mark Hinkle asks: <a href="https://thenewstack.io/has-serverless-jumped-the-shark/?ref=daveabrock.com" rel="nofollow">has serverless jumped the shark?</a></li><li>Steve Smith <a href="https://ardalis.com/csharp-generics-best-practices/?ref=daveabrock.com" rel="nofollow">writes about C# generics best practices</a>.</li><li>Joydip Kanjilal <a href="https://www.developer.com/web-services/best-practices-restful-api/?ref=daveabrock.com" rel="nofollow">writes about best practices for designing RESTful APIs</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-199-redis-with-guy-royse/?ref=daveabrock.com" rel="nofollow">talks to Guy Royse about Redis</a>.</li><li>The Adventures in .NET Podcast <a href="https://devchat.tv/adventures-in-dotnet/uno-platform-isnt-a-card-game-net-072/?ref=daveabrock.com" rel="nofollow">talks about Uno Platform</a>.</li><li>The Xamarin Podcast <a href="https://www.xamarinpodcast.com/94?ref=daveabrock.com" rel="nofollow">talks about .NET MAUI</a>.</li><li>Jesse Liberty <a href="http://jesseliberty.com/2021/06/05/jeff-fritz-on-blazor-azure-much-more/?ref=daveabrock.com" rel="nofollow">talks to Jeff Fritz about Blazor and Azure</a>.</li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1743&ref=daveabrock.com" rel="nofollow">talks to Jeremy Miller about event sourcing</a>.</li><li>The Coding Blocks Podcast <a href="https://www.codingblocks.net/podcast/designing-data-intensive-applications-single-leader-replication/?ref=daveabrock.com" rel="nofollow">continues talking about the DDIA book</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=apwB2U4cKfU&ref=daveabrock.com" rel="nofollow">work on local development with Azure Static Web Apps</a>.</li><li>On .NET <a href="https://channel9.msdn.com/Shows/On-NET/Feature-flags-with-NET-and-Azure-App-Configuration?ref=daveabrock.com" rel="nofollow">talks to Scott Addie about feature flags and Azure App Configuration in .NET</a>, <a href="https://dev.to/dotnet/on-net-episode-setting-up-observability-in-orleans-2dja?ref=daveabrock.com" rel="nofollow">sets up observability in Orleans</a>, <a href="https://www.youtube.com/watch?v=Q4D5NffKTIk&ref=daveabrock.com">talks to Ed Charbeneau about Blazor components</a>, and <a href="https://www.youtube.com/watch?v=bXsOOpWavp4&ref=daveabrock.com">discusses nullable reference types</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Your guide to REST API versioning in ASP.NET Core ]]></title>
        <description><![CDATA[ In this post, we learn how to use API versioning in ASP.NET Core. ]]></description>
        <link>https://www.daveabrock.com/2021/06/16/rest-api-versioning-aspnet-core/</link>
        <guid isPermaLink="false">6092e0fbf4327a003ba304d0</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 16 Jun 2021 08:39:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1535231540604-72e8fbaf8cdb?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxjaGFuZ2V8ZW58MHx8fHwxNjIwMjM4NzM5&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post was originally published on the <a href="https://www.telerik.com/blogs/your-guide-rest-api-versioning-aspnet-core?ref=daveabrock.com">Telerik Developer Blog.</a></em></p><p>When you ship an API, you're inviting developers to consume it based on an agreed-upon contract. So what happens if the contract changes? Let's look at a simple example.</p><p>If I call an API with a URL of <code>https://mybandapi.com/api/bands/4</code>, I'll get the following response:</p><!--kg-card-begin: markdown--><pre><code class="language-json">{
  &quot;id&quot;: 4,
  &quot;name&quot;: &quot;The Eagles, man&quot;
}
</code></pre>
<!--kg-card-end: markdown--><p>Now, let's say I decide to update my API schema with a new field, <code>YearFounded</code>. Here's how the new response looks now:</p><!--kg-card-begin: markdown--><pre><code class="language-json">{
  &quot;id&quot;: 4,
  &quot;name&quot;: &quot;The Eagles, man&quot;,
  &quot;YearFounded&quot;: 1971
}
</code></pre>
<!--kg-card-end: markdown--><p>With this new field, existing clients still work. It's a non-breaking change, as existing apps can happily ignore it. You should document the new field in The Long Run, for sure, but it isn't a huge deal at the end of the day.</p><p>Let's say you want the <code>name</code> to be instead a collection of <code>names</code> associated with the band, like this:</p><pre><code class="language-json">{
  "id": 4,
  "names": 
  [
    "The Eagles, man",
    "The Eagles"
  ],
  "FoundedYear": 1971
}
</code></pre><p>You introduced a <em>breaking change</em>. Your consumers expected the <code>name</code> field to be a string value, and now you're returning a collection of strings. As a result, when consumers call the API, their applications will not work as intended, and your users are not going to Take It Easy.</p><p>Whether it's a small non-breaking change or one that breaks things, your consumers need to know what to expect. To help manage your evolving APIs, you'll need an API versioning strategy.</p><p>Since ASP.NET Core 3.1, Microsoft has <a href="https://github.com/microsoft/aspnet-api-versioning?ref=daveabrock.com">provided libraries</a> to help with API versioning. It provides a simple and powerful way to add versioning semantics to your REST services and is also compliant with the <a href="https://github.com/Microsoft/api-guidelines?ref=daveabrock.com">Microsoft REST Guidelines</a>. In this post, I'll show you how you can use the <code>Microsoft.AspNetCore.Mvc.Versioning</code> NuGet package to apply API versioning to ASP.NET Core REST web APIs. </p><p>We're going to look through various approaches to versioning your APIs and how you can enable the functionality in ASP.NET Core. Which approach should you use? As always, It Depends™. There's no dogmatic "one size fits all" approach to API versioning. Instead, use the approach that works best for your situation. </p><h2 id="get-started">Get Started</h2><p>To get started, you'll need to grab the <code>Microsoft.AspNetCore.Mvc.Versioning</code> NuGet package. The easiest way is through the .NET CLI. Execute the following command from your project's directory:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.Mvc.Versioning</code></pre><p>With the package installed in your project, you'll need to add the service to ASP.NET Core's dependency injection container. From <code>Startup.ConfigureServices</code>, add the following:</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
   services.AddApiVersioning();
   // ..
}</code></pre><p>What happens when I make a GET request on <code>https://mybandapi.com/api/bands/4</code>? I'm greeted with the following <code>400 Bad Request</code> response:</p><pre><code class="language-json">{
    "error": {
        "code": "ApiVersionUnspecified",
        "message": "An API version is required, but was not specified.",
        "innerError": null
    }
}</code></pre><p>By default, you need to append <code>?api-request=1.0</code> to the URL to get this working, like this:</p><pre><code>https://mybandapi.com/api/bands/4?api-request=1.0</code></pre><p>This isn't a great developer experience. To help this, we can introduce a default version. If consumers don't explicitly include a version in their request, we'll assume they want to use v1.0. Our library takes in an <code>ApiVersioningOptions</code>type, which we can use to specify a default version. So you're telling the consumers, "If you don't opt-in to another version, you'll be using v1.0 of our API."</p><p>In <code>Startup.ConfigureServices</code>, update your <code>AddApiVersioning</code> code to this:</p><pre><code class="language-csharp">services.AddApiVersioning(options =&gt;
{
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion(1, 0);
});</code></pre><p>With this in place, your consumers should be able to call a default version from <code>https://mybandapi.com/api/bands/4</code>.</p><h2 id="introducing-multiple-versions-for-a-single-endpoint">Introducing Multiple Versions for a Single Endpoint</h2><p>Let's say we want to work with two versions of our API, 1.0 and 2.0. We can use this by decorating our controller with an <code>ApiVersionAttribute</code>.</p><pre><code class="language-csharp">[Produces("application/json")]
[Route("api/[controller]")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class BandsController : ControllerBase
{}</code></pre><p>Once I do that, I can use the <code>MapToApiVersionAttribute</code> to let ASP.NET Core know which action methods are mapped to my API versions. In my case, I've got two methods wired up to a GET on <code>api/bands</code>, <code>GetById</code> and <code>GetById20</code>. </p><p>Here's how the annotations look:</p><pre><code class="language-csharp">[MapToApiVersion("1.0")]
[HttpGet("{id}")]
public async Task&lt;ActionResult&lt;Band&gt;&gt; GetById(int id)
{}

[MapToApiVersion("2.0")]
[HttpGet("{id}")]
public async Task&lt;ActionResult&lt;Band&gt;&gt; GetById20(int id)
{}</code></pre><p>With this, the controller will execute the 1.0 version of the <code>GetById</code> with the normal URI (or <code>/api/bands/4?api-version=1.0</code>) and the controller executes the 2.0 version when the consumer uses <code>https://mybandapi.com/api/bands/4?api-version=2.0</code>.</p><p>Now that we're supporting multiple versions, it's a good idea to let your consumers know which versions your endpoints are supporting. To do this, you can use the following code to report API versions to the client.</p><pre><code class="language-csharp">services.AddApiVersioning(options =&gt;
{
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.ReportApiVersions = true;
});</code></pre><p>When you do this, ASP.NET Core provides an <code>api-supported-versions</code> response header that shows which versions an endpoint supports.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/versions-response.jpg" class="kg-image" alt loading="lazy" width="1222" height="342" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/versions-response.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/versions-response.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/versions-response.jpg 1222w" sizes="(min-width: 720px) 720px"></figure><p>By default, the library supports versioning from query strings. I like this method. Your clients can opt-in to new versions when they're ready. And if no version is specified, consumers can rely on the default version.</p><p>Of course, this is not the only way to version an API. Aside from query strings, we'll look at other ways you can version your APIs in ASP.NET Core:</p><ul><li>URI/URL path</li><li>Custom request headers </li><li>Media versioning with Accept headers</li></ul><h2 id="versioning-with-a-uri-path">Versioning with a URI Path</h2><p>If I want to version with the familiar <code>/api/v{version number}</code> scheme, I can do it easily. Then, from the top of my controller, I can use a <code>RouteAttribute</code> that matches my API version. Here's how my controller annotations look now:</p><pre><code class="language-csharp">[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class BandsController : ControllerBase
{}
</code></pre><p>Then, when I call my API from <code>api/v2/bands/4</code>, I will be calling version 2 of my API. While this is a popular method and is easy to set up, it doesn't come without drawbacks. It doesn't imply a default version, so clients might feel forced to update the URIs throughout their apps whenever a change occurs.</p><p>Whether it's using a query string or the URI path, <code>Microsoft.AspNetCore.Mvc.Versioning</code> makes it easy to work with versioning from the URI level. Many clients might prefer to do away with URI versioning for various reasons. In these cases, you can use headers.</p><h2 id="custom-request-headers">Custom Request Headers</h2><p>If you want to leave your URIs alone, you can have consumers pass a version from a request header. For example, if consumers want to use a non-default version of my API, I can have them pass in a <code>X-Api-Version</code> request header value. </p><p>When moving to headers, also consider that you're making API access a little more complicated. Instead of hitting a URI, clients need to hit your endpoints programmatically or from API tooling. This might not be a huge jump for your clients, but is something to consider.</p><p>To use custom request headers, you can set the library's <code>ApiVersionReader</code> to a <code>HeaderApiVersionReader</code>, then passing in the header name. (If you want to win Trivia Night at the pub, the answer to "What is the default <code>ApiVersionReader</code>?" is "<code>QueryStringApiVersionReader</code>." )</p><pre><code class="language-csharp">services.AddApiVersioning(options =&gt;
{
   options.DefaultApiVersion = new ApiVersion(2, 0);
   options.AssumeDefaultVersionWhenUnspecified = true;
   options.ReportApiVersions = true;
   options.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version");
});</code></pre><p>In Postman, I can pass in an <code>X-Api-Version</code> value to make sure it works. And it does.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/versions-request-header.jpg" class="kg-image" alt loading="lazy" width="1560" height="330" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/versions-request-header.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/versions-request-header.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/versions-request-header.jpg 1560w" sizes="(min-width: 720px) 720px"></figure><h2 id="media-versioning-with-accept-headers">Media Versioning with Accept Headers</h2><p>When a client passes a request to you, they use an <code>Accept</code> header to control the format of the request it can handle. These days, the most common <code>Accept</code> value is the media type of <code>application/json</code>. We can use versioning with our media types, too. </p><p>To enable this functionality, change <code>AddApiVersioning</code> to the following:</p><pre><code class="language-csharp">services.AddApiVersioning(options =&gt;
{
     options.DefaultApiVersion = new ApiVersion(1, 0);
     options.AssumeDefaultVersionWhenUnspecified = true;
     options.ReportApiVersions = true;
     options.ApiVersionReader = new MediaTypeApiVersionReader("v");
});</code></pre><p>Clients can then pass along an API version with an <code>Accept</code> header, as follows.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/versions-media-header.jpg" class="kg-image" alt loading="lazy" width="1787" height="395" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/versions-media-header.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/versions-media-header.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/versions-media-header.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/versions-media-header.jpg 1787w" sizes="(min-width: 720px) 720px"></figure><h2 id="combining-multiple-approaches">Combining Multiple Approaches</h2><p>When working with the <code>Microsoft.AspNetCore.Mvc.Versioning</code> NuGet package, you aren't forced into using a single versioning method. For example, you might allow clients to choose between passing in a query string or a request header. The <code>ApiVersionReader</code> supports a static <code>Combine</code> method that allows you to specify multiple ways to read versions.</p><pre><code class="language-csharp">services.AddApiVersioning(options =&gt;
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
    options.ApiVersionReader =
    ApiVersionReader.Combine(
       new HeaderApiVersionReader("X-Api-Version"),
       new QueryStringApiVersionReader("version"));
});</code></pre><p>With this in place, clients get v2.0 of our API by calling <code>/api/bands/4?version=2</code> or specifying a <code>X-Api-Version</code> header value of <code>2</code> .</p><h2 id="learn-more">Learn More</h2><p>This post only scratches the surface—there's so much more you can do with the <code>Microsoft.AspNetCore.Mvc.Versioning</code> NuGet package. For example, you can <a href="https://github.com/microsoft/aspnet-api-versioning/wiki/New-Services-Quick-Start?ref=daveabrock.com#aspnet-web-api-with-odata-v40">work with OData</a> and enable a <a href="https://github.com/microsoft/aspnet-api-versioning/wiki/New-Services-Quick-Start?ref=daveabrock.com#aspnet-web-api-with-odata-v40">versioned API explorer</a>, enabling you to add versioned documentation to your services. If you don't enjoy decorating your controllers and methods with attributes, you can use the <a href="https://github.com/microsoft/aspnet-api-versioning/wiki/Controller-Conventions?ref=daveabrock.com">controller conventions approach</a>.</p><p>Check out <a href="https://github.com/microsoft/aspnet-api-versioning/wiki/API-Version-Reader?ref=daveabrock.com">the library's documentation for details</a>, and make sure to read up <a href="https://github.com/microsoft/aspnet-api-versioning/wiki/Known-Limitations?ref=daveabrock.com">on known limitations</a> (especially if you have advanced ASP.NET Core routing considerations).</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Upgrading a Blazor WebAssembly Azure Static Web App from .NET 5 to .NET 6 ]]></title>
        <description><![CDATA[ In this post, I briefly discuss the process of upgrading a Blazor WebAssembly App from .NET 5 to .NET 6. ]]></description>
        <link>https://www.daveabrock.com/2021/06/15/upgrade-blazor-static-app-net-5-net-6/</link>
        <guid isPermaLink="false">60c92ecc9caef9003b75e1b9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 15 Jun 2021 18:30:50 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1602212096437-d0af1ce0553e?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIxfHxhc3Ryb25hdXR8ZW58MHx8fHwxNjIzNzk4NjIz&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>In the last year or so, I've been working on a Blazor WebAssembly project called <a href="https://www.daveabrock.com/tag/blast-off-blazor/">Blast Off with Blazor</a>. It's <a href="https://github.com/daveabrock/NASAImageOfDay?ref=daveabrock.com">a Blazor WebAssembly app</a> hosted on the Azure Static Web Apps service, <a href="https://www.daveabrock.com/2021/05/13/azure-static-web-apps-favorite-things/">which recently went GA</a>. Right now, it consists of four small projects: an Azure Functions API project, a project for the Blazor WebAssembly bits, a project to share models between the two, and a test project.</p><p>I wanted to see how easily I could upgrade the Blazor project from .NET 5 to .NET 6. With <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com">.NET 6 now on Preview 4</a>, it's evolved enough where I'm ready for an upgrade. I was hoping I could double-click the project file, change my client and test projects from <strong>net5.0 </strong>to <strong>net6.0</strong>, and be on my way. (I also know I was being very optimistic.)  </p><p>After upgrading the TFM, I was able to run the app successfully. Great. I started this app using .NET 5 and its mature API surface, so I didn't expect any issues there.  The interesting part is deploying it to Azure Static Web Apps. Azure Static Web Apps uses the Oryx build system and I wasn't too sure if it supported .NET 6 yet. It does, and it deployed to Azure Static Web Apps on the first try.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/06/oryx-60.png" class="kg-image" alt loading="lazy" width="1153" height="879" srcset="https://www.daveabrock.com/content/images/size/w600/2021/06/oryx-60.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/06/oryx-60.png 1000w, https://www.daveabrock.com/content/images/2021/06/oryx-60.png 1153w" sizes="(min-width: 720px) 720px"></figure><h2 id="what-about-upgrading-azure-functions-to-net-6">What about upgrading Azure Functions to .NET 6?</h2><p>Recently, the Azure Functions team <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/what-s-new-with-net-on-azure-functions-june-2021/ba-p/2428669?ref=daveabrock.com">announced initial support of running Azure Functions on .NET 6</a>. This <em>currently</em> requires running a preview release of Azure Functions Core Tools V4. So, I could get this working locally but the support won't come to Azure Static Web Apps <a href="https://twitter.com/nthonyChu/status/1404594114436370435?ref=daveabrock.com">until we get closer to .NET 6 GA in November 2021</a>. I'll upgrade it then. For me, I'd rather upgrade the Blazor project so I can take advantage of things like hot reload, AOT, and JSON serialization improvements.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #53: 🚀 This issue was compiled ahead of time ]]></title>
        <description><![CDATA[ This week, we talk about Blazor WebAssembly AOT and get updates from the community. ]]></description>
        <link>https://www.daveabrock.com/2021/06/13/dotnet-stacks-53/</link>
        <guid isPermaLink="false">60bb69ca941321003e21c266</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 13 Jun 2021 01:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/06/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday, all. I wanted to thank everybody for the birthday wishes as the newsletter turned 1 last week. Also, welcome to all the new subscribers!</p><p>This week wasn't as crazy as we're recovering from Build, but as always, there's plenty to discuss. Let's get started. </p><ul><li>One big thing: Taking a look at Blazor WebAssembly AOT</li><li>The little things: NuGet improvements in Visual Studio, Tye gets a VS Code extension</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-taking-a-look-at-blazor-webassembly-aot">One big thing: Taking a look at Blazor WebAssembly AOT</h2><p>With Blazor, <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-5.0&ref=daveabrock.com">you've got two hosting models</a> to consider, Blazor Server and Blazor WebAssembly. </p><p>With Blazor Server, your download size isn't a concern. You can leverage server capabilities with all the .NET-compatible APIs, and you can use thin-clients—you will, however, you need to consider the higher latency and scale if you have a lot of concurrent users. (Unless you have <em>a lot</em> of concurrent connections, it likely won't be an issue.)  With Blazor WebAssembly, you can leverage client capabilities and a fully functioning app once the client downloads it. If you want to embrace Jamstack principles with a SPA calling off to serverless APIs (with attractive options like Azure Static Web Apps), Blazor WebAssembly is a nice option. The download size is larger, and apps do take significantly longer to load, though.</p><p>In my experience across the community, I do see many Blazor scenarios geared towards Blazor Server. Many times, folks are also packaging an ASP.NET Core API, and the download size and loading times of WebAssembly might be holding people back. "I want to wait until we get AOT," I've heard a lot of people say.  </p><p>Last week, with .NET 6 Preview 4, Blazor ahead-of-time compilation (AOT) <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-webassembly-ahead-of-time-aot-compilation">is finally here</a>. With AOT, you can compile .NET code directly to WebAssembly to help boost runtime performance. Before AOT, Blazor WebAssembly apps run from a .NET IL interpreter, meaning the .NET WebAssembly code is significantly slower than a normal .NET runtime (like with Blazor Server). </p><p>I gave it a go using Steve Sanderson's <a href="https://github.com/SteveSandersonMS/PictureFixer?ref=daveabrock.com">Picture Fixer app</a> featured in Build talks and the .NET 6 Preview 4 release announcement. As mentioned in the announcement, you need to do two things:</p><ul><li>Install the Blazor WebAssembly AOT build tools as an optional .NET SDK workload</li><li>Add <code>&lt;RunAOTCompilation&gt;true&lt;/RunAOTCompilation&gt;</code> to your project file</li></ul><p>Then, you'll need to publish your application. On my beefy Dell XPS 15 and its 64 gigs of RAM, it took almost 15 minutes to AOT 15 assemblies and use the <a href="https://emscripten.org/docs/tools_reference/emcc.html?ref=daveabrock.com">Emscripten toolchain</a> to do the heavy lifting. The team notes they are working on speeding this up, but it's good to note this wait only occurs during publish time and not local development. With AOT in place, you can see dramatic changes in data-intensive tasks specifically. </p><p>As with the decision to go with Blazor Server or Blazor WebAssembly, you need to consider tradeoffs when introducing AOT with your Blazor projects. As AOT-compiled projects are typically double the size, you need to consider the value of trading off load time performance for runtime performance. You can pick and choose when you use AOT, of course, so typical use cases would take a hybrid approach and leveraging AOT specifically for data-intensive tasks. </p><p>When Steve Sanderson <a href="https://www.daveabrock.com/2021/01/17/dev-discussions-steve-sanderson/">talked to us</a> a while back, he said:</p><blockquote>If we can get Blazor WebAssembly to be faster than JS in typical cases (via AoT compilation, which is very achievable) and somehow simultaneously reduce download sizes to the point of irrelevance, then it would be very much in the interests of even strongly JS-centric teams to reconsider and look at all the other benefits of C#/.NET too.</blockquote><p>AOT is a big step in that direction. The size of the .NET runtime will never compare to small JS frameworks, but getting close to download size and performance will be a giant step towards providing a modern, fast SWA solution for folks open to the .NET ecosystem.</p><hr><h2 id="nuget-improvements-in-visual-studio-tye-gets-a-vs-code-extension">NuGet improvements in Visual Studio, Tye gets a VS Code extension</h2><p>Last week, Christopher Gill <a href="https://devblogs.microsoft.com/nuget/intellicode-package-suggestions-for-nuget-in-visual-studio/?ref=daveabrock.com">announced that Visual Studio is introducing NuGet Package Suggestions in Visual Studio 16.10</a>. With IntelliCode Package Suggestions, NuGet uses your project's metadata—like what packages you have installed and your project type—to suggest packages you might need. Package suggestions are shown in the NuGet Package Manager UI before you enter a search query.</p><p>As for the fine print, it currently only works on the project level and does not suggest packages outside of <em>nuget.org. </em>Also, it won't support deprecated packages or ones that are transitively installed. </p><hr><p>Also from last week, Microsoft <a href="https://devblogs.microsoft.com/dotnet/announcing-visual-studio-code-extension-for-tye/?ref=daveabrock.com">rolled out a Visual Studio Code extension for Tye</a>. If you aren't familiar Project Tye is an open-source project that <a href="https://www.daveabrock.com/2020/08/19/microservices-with-tye-1/">helps developers work with microservices and distributed applications</a>.</p><p>We're seeing a lot of nice updates for Tye, and I wonder when it'll get out of the "it's experimental, things might break" phase. For example, the official repo on GitHub still states: "<em>Project Tye is an open source experiment at the moment. We are using this time to try radical ideas to improve microservices developer productivity and see what works...For the duration of the experiment, consider every part of the tye experience to be volatile.</em>" It has a lot of nice use cases with Dapr, for example, and I'd love to see when Microsoft is going to put a ring on it.</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>David Pine <a href="https://www.twilio.com/blog/build-video-chat-app-asp-net-core-angular-11-twilio-programmable-video?ref=daveabrock.com" rel="nofollow">builds a video chat app with ASP.NET Core 5.0, Angular 11, and Twilio Programmable Video</a>.</li><li>Christopher Gill <a href="https://devblogs.microsoft.com/nuget/intellicode-package-suggestions-for-nuget-in-visual-studio?ref=daveabrock.com" rel="nofollow">introduces IntelliCode package suggestions for NuGet in Visual Studio</a>.</li><li>Mark Downie <a href="https://www.poppastring.com/blog/interpreting-async-code-in-cpu-traces?ref=daveabrock.com" rel="nofollow">interprets async code in CPU traces</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Jon Galloway <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-version-8-10-is-now-available?ref=daveabrock.com" rel="nofollow">announces Visual Studio 2019 for Mac version 8.10</a>.</li><li>Pratik Sanglikar <a href="https://devblogs.microsoft.com/dotnet/announcing-visual-studio-code-extension-for-tye?ref=daveabrock.com" rel="nofollow">announces the Visual Studio Code extension for Tye</a>.</li><li>Dapr 1.2 <a href="https://blog.dapr.io/posts/2021/05/27/dapr-v1.2-is-now-available/?ref=daveabrock.com" rel="nofollow">is now available</a>.</li><li>Josh Love <a href="https://devblogs.microsoft.com/azure-sdk/introducing-the-new-azure-function-extension-libraries-beta/?ref=daveabrock.com" rel="nofollow">introduces the Azure Functions extension libraries for the Azure SDK</a>.</li><li>In JetBrains news, Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/06/01/investigate-memory-issues-with-ease-introducing-real-time-inspections-in-dotmemory-allocation-analysis/?ref=daveabrock.com" rel="nofollow">introduces real-time inspections in dotMemory Allocation Analysis</a>, Alexander Kurakin <a href="https://blog.jetbrains.com/dotnet/2021/05/31/rider-2021-2-eap/?ref=daveabrock.com" rel="nofollow">announces an EAP for Rider 2021.2</a> and <a href="https://blog.jetbrains.com/dotnet/2021/05/31/resharper-2021-2-eap/?ref=daveabrock.com" rel="nofollow">ReSharper 2021.2</a>, and Cake <a href="https://cakebuild.net/blog/2021/06/cake-rider-1.0.0-released?ref=daveabrock.com" rel="nofollow">for Rider 1.0 is released</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Aaron Stannard <a href="https://aaronstannard.com/dotnetoss-free-lunch-ends/?ref=daveabrock.com" rel="nofollow">chimes in on the IdentityServer drama</a>.</li><li>For community standups: Xamarin <a href="https://www.youtube.com/watch?v=cObI_rRCEcY&ref=daveabrock.com">recaps Build 2021</a>, and Entity Framework <a href="https://www.youtube.com/watch?v=XdhX3iLXAPk&ref=daveabrock.com">introduces EF Core compiled models</a>.</li><li>Stack Overflow <a href="https://techcrunch.com/2021/06/02/stack-overflow-acquired-by-prosus-for-a-reported-1-8-billion/?ref=daveabrock.com">was acquired for $1.8 billion</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Hassan Habib <a href="https://devblogs.microsoft.com/aspnet/building-contextual-experiences-w-blazor?ref=daveabrock.com" rel="nofollow">builds contextual experiences with Blazor</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/blazor/contentful/2021/05/29/Blazor-and-Contentful-CMS-Blog-Template.html?ref=daveabrock.com" rel="nofollow">builds a template using Blazor and Contentful CMS</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/create-connect-4-blazor-webassembly-in-hour?ref=daveabrock.com" rel="nofollow">builds a Connect 4 game with Blazor</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/05/31/verify-vaccination-data-using-zero-knowledge-proofs-with-asp-net-core-and-mattr/?ref=daveabrock.com" rel="nofollow">verifies vaccination data with ASP.NET Core and Mattr</a>.</li><li>Gopi Govindasamy <a href="https://www.syncfusion.com/blogs/post/how-to-dynamically-render-a-component-in-a-blazor-application.aspx?ref=daveabrock.com" rel="nofollow">dynamically renders a component in a Blazor app</a>.</li><li>Jon Hilton <a href="https://jonhilton.net/choosing-a-blazor-component-library/?ref=daveabrock.com" rel="nofollow">walks through choosing a Blazor component library</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/asynchronous-programming-with-async-and-await-in-asp-net-core/?ref=daveabrock.com" rel="nofollow">writes about asynchronous programming with async and await in ASP.NET Core</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Kristoffer Strube <a href="https://blog.elmah.io/new-linq-extensions-in-net-6-and-benchmarks/?ref=daveabrock.com" rel="nofollow">writes about new LINQ extensions in .NET 6</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-the-net-type-system?ref=daveabrock.com" rel="nofollow">posts a discussion about the .NET type system</a> and <a href="https://devblogs.microsoft.com/dotnet/conversation-about-net-interop?ref=daveabrock.com" rel="nofollow">about .NET interop</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/benchmarking-4-reflection-methods-for-calling-a-constructor-in-dotnet/?ref=daveabrock.com" rel="nofollow">benchmarks various reflection methods for calling a constructor in .NET</a>.</li><li>Christos Matskas <a href="https://dev.to/425show/secure-and-minimal-apis-using-net-6-c-10-and-azure-active-directory-197i?ref=daveabrock.com" rel="nofollow">writes about secure and minimal APIs using .NET 6, C# 10, and Azure Active Directory</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/working-with-dotnet-six-priorityqueue?ref=daveabrock.com" rel="nofollow">works with the PriorityQueue in .NET 6</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Maarten Balliauw <a href="https://blog.maartenballiauw.be/post/2021/06/01/custom-bindings-with-azure-functions-dotnet-isolated-worker.html?ref=daveabrock.com" rel="nofollow">uses custom bindings with the Azure Functions .NET isolated worker</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/058-azure-service-bus-introduction?ref=daveabrock.com" rel="nofollow">introduces using Azure Service Bus with C#</a>.</li><li>Théo Rémy <a href="https://medium.com/asos-techblog/stateful-serverless-workflows-with-azure-durable-functions-44986abc121b?ref=daveabrock.com" rel="nofollow">works on stateful serverless workflows with Azure Durable Functions</a>.</li><li>Thomas Maurer <a href="https://www.thomasmaurer.ch/2021/06/run-cloud-native-apps-on-azure-paas-anywhere/?ref=daveabrock.com" rel="nofollow">runs cloud-native apps on Azure PaaS anywhere</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Abhijit Jana <a href="https://dailydotnettips.com/switch-between-git-repositories-and-branches-seamlessly-in-visual-studio/?ref=daveabrock.com" rel="nofollow">switches between Git branches and repos in Visual Studio</a> and <a href="https://dailydotnettips.com/remove-unused-references-clean-up-project-references-and-nuget-packages-in-visual-studio/?ref=daveabrock.com" rel="nofollow">removes unused references in Visual Studio</a>.</li><li>Nicholas Blumhardt <a href="https://nblumhardt.com/2021/06/customize-serilog-text-output/?ref=daveabrock.com" rel="nofollow">customizes Serilog text output</a>.</li><li>Russell Smith <a href="https://petri.com/guide-getting-started-with-windows-package-manager-winget-v1-0?ref=daveabrock.com" rel="nofollow">gets started with the Windows Package Manager</a>, and Matthew MacDonald <a href="https://medium.com/young-coder/winget-goes-mainstream-but-still-lags-behind-213404148206?ref=daveabrock.com" rel="nofollow">offers his honest appraisal</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>James Montemagno <a href="https://devblogs.microsoft.com/xamarin/building-beautiful-apps-with-xamarin-forms?ref=daveabrock.com" rel="nofollow">writes about building beautiful apps with Xamarin</a>.</li><li>Luis Matos <a href="https://luismts.com/msbuild-dotnetmaui-preview-4/?ref=daveabrock.com" rel="nofollow">recaps .NET MAUI Preview 4</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-10?ref=daveabrock.com" rel="nofollow">provides his weekly MAUI update</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Jimmy Bogard <a href="https://jimmybogard.com/domain-driven-refactoring-intro/?ref=daveabrock.com" rel="nofollow">starts a series on domain-driven refactoring</a>.</li><li>Vladimir Khorikov <a href="https://enterprisecraftsmanship.com/posts/nulls-in-value-objects/?ref=daveabrock.com" rel="nofollow">writes about nulls in value objects</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/competing-consumers-pattern-for-scalability/?ref=daveabrock.com" rel="nofollow">talks about the Competing Consumers Pattern</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The Overflow <a href="https://stackoverflow.blog/2021/06/01/podcast-343-unpacking-observability-and-opentelemetry-with-spiros-xanthos-of-splunk/?ref=daveabrock.com" rel="nofollow">talks about observability and OpenTelemetry</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-198-dapr-with-cecil-phillip/?ref=daveabrock.com" rel="nofollow">talks to Cecil Phillip about Dapr</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/microsoft-build-recap-2021-episode-143?ref=daveabrock.com" rel="nofollow">recaps Build 2021</a>, and <a href="https://www.mergeconflict.fm/256?ref=daveabrock.com">so does Merge Conflict</a>.</li><li>The No Dogma Podcast <a href="https://nodogmapodcast.bryanhogan.net/?ref=daveabrock.com" rel="nofollow">talks to Martin Beeby about using .NET on AWS</a>.</li><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-77-application-security-with-tanya-janka/?ref=daveabrock.com" rel="nofollow">talks to Tanya Janka about application security</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=EOlm3ft0VPo&ref=daveabrock.com" rel="nofollow">deploys with GitHub Actions</a>.</li><li>On .NET <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-String-Interpolation?ref=daveabrock.com" rel="nofollow">talks about C# string interpolation</a> and <a href="https://www.youtube.com/watch?v=gEKph1QmEpE&ref=daveabrock.com" rel="nofollow">async streams</a>.</li><li>Technology and Friends <a href="https://www.davidgiard.com/2021/05/31/JeffWilcoxOnOpenSourceAndMicrosoft.aspx?ref=daveabrock.com" rel="nofollow">talks to Jeff Wilcox about open source at Microsoft</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/How-to-Set-up-Azure-Monitor-for-SQL-Insights?ref=daveabrock.com" rel="nofollow">sets up Azure Monitor for SQL Insights</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Low Ceremony, High Value: A Tour of Minimal APIs in .NET 6 ]]></title>
        <description><![CDATA[ In this post, let&#39;s take a tour of Minimal APIs in .NET 6. ]]></description>
        <link>https://www.daveabrock.com/2021/06/09/low-ceremony-high-value-a-tour-of-minimal-apis-in-net-6/</link>
        <guid isPermaLink="false">60b8a80b941321003e21bec2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 09 Jun 2021 09:54:40 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1527567018838-584d3468eb85?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDM3fHxtaW5pbWFsfGVufDB8fHx8MTYyMzI1MDM2OA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This post was originally published on the <a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6?ref=daveabrock.com">Telerik Blog</a>.</em></p><p>When developing APIs in ASP.NET Core, you're traditionally forced into using ASP.NET Core MVC. Going against many of the core tenets of .NET Core, MVC projects give you everything <em>and </em>the kitchen sink. After creating a project from the MVC template and noticing all that it contains, you might be thinking: all <em>this</em> to get some products from a database? Unfortunately, with MVC it requires so much ceremony to build an API.</p><p>Looking at it another way: if I'm a new developer or a developer looking at .NET for the first time (or after a long break), it's a frustrating experience—not only do I have to learn how to build an API, I have to wrap my head around all I have to do in ASP.NET Core MVC. If I can build services in Node with just a few lines of code, why can't I do it in .NET? </p><p>Starting with .NET 6 Preview 4, you can. The ASP.NET team has <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#introducing-minimal-apis">rolled out Minimal APIs</a>, a new, simple way to build small microservices and HTTP APIs in ASP.NET Core. Minimal APIs hook into ASP.NET Core's hosting and routing capabilities and allow you to build fully functioning APIs with just a few lines of code. This does not replace building APIs with MVC—if you are building complex APIs or prefer MVC, you can keep using it as you always have—but its a nice approach to writing no-frills APIs. </p><p>In this post, I'll give you a tour of Minimal APIs. I'll first walk you through how it will work with .NET 6 and C# 10. Then, I'll describe how to start playing with the preview bits today. Finally, we'll look at the path forward.</p><h2 id="write-a-minimal-api-with-three-lines-of-code">Write a Minimal API with Three Lines of Code</h2><p>If you want to create a Minimal API, you can make a simple GET request with just three lines of code.</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.MapGet("/", () =&gt; "Hello World!");
await app.RunAsync();</code></pre><p>That's it! When I run this code, I'll get a <code>200 OK</code> response with the following:  </p><pre><code>HTTP/1.1 200 OK
Connection: close
Date: Tue, 01 Jun 2021 02:52:42 GMT
Server: Kestrel
Transfer-Encoding: chunked

Hello World!</code></pre><p>How is this even possible? Thanks to top-level statements, <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/top-level-statements?ref=daveabrock.com">a welcome C# 9 enhancement</a>, you can execute a program without a namespace declaration, class declaration, or even a <code>Main(string[] args</code> method. This alone saves you nine lines of code. Even without the <code>Main</code> method, we can still infer arguments—the compiler takes care of this for you.</p><p>You'll also notice the absence of <code>using</code> statements. This is because by default, in .NET 6, ASP.NET Core <a href="https://github.com/dotnet/aspnetcore/issues/32451?ref=daveabrock.com">will use global usings</a>—a new way to declare your <code>usings</code> in a single file, avoiding the need to declare them in individual source files. I can keep my global usings in a devoted <code>.usings</code> file, as you'll see here:</p><pre><code class="language-csharp">global using System;
global using System.Net.Http;
global using System.Threading.Tasks;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.DependencyInjection;
</code></pre><p>If you've worked with Razor files in ASP.NET Core, this is similar to using a <code>_Imports.razor</code> file that allows you to keep <code>@using</code> directives out of your Razor views. Of course, this will be out-of-the-box behavior but doesn't have to replace what you're doing now. Use what works best for you. </p><p>Going back to the code, after creating a <code>WebApplication</code> instance, ASP.NET Core uses <code>MapGet</code> to add an endpoint that matches any <code>GET</code> requests to the root of the API. Right now, I'm only returning a string. I can use lambda improvements to C# 10 to pass in a callback—common use cases might be a model or an Entity Framework context. We'll provide a few examples to show off its flexibility.</p><h2 id="use-httpclient-with-minimal-apis">Use HttpClient with Minimal APIs</h2><p>If you're writing an API, you're likely using <code>HttpClient</code> to consume APIs yourself. In my case, I'll use the <code>HttpClient</code> to call off to the <a href="https://github.com/jamesseanwright/ron-swanson-quotes?ref=daveabrock.com">Ron Swanson Quotes API</a> to get some inspiration. Here's how I can make a <code>async</code> call to make this happen:</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.MapGet("/quote", async () =&gt; 
    await new HttpClient().GetStringAsync("https://ron-swanson-quotes.herokuapp.com/v2/quotes"));
await app.RunAsync();</code></pre><p>When I execute this response, I'll get a wonderful quote that I will never disagree with:</p><pre><code>HTTP/1.1 200 OK
Connection: close
Date: Fri, 04 Jun 2021 11:27:47 GMT
Server: Kestrel
Transfer-Encoding: chunked

["Dear frozen yogurt, you are the celery of desserts. Be ice cream or be nothing. Zero stars."]</code></pre><p>In more real-world scenarios, you'll probably call <code>GetFromJsonAsync</code> with a model, but that can be done just as easily. Speaking of models, let's take a look to see how that works.</p><h2 id="work-with-models">Work with Models </h2><p>With just an additional line of code, I can work with a <code>Person</code> record. Records, also a C# 9 feature, are reference types that use value-based equality and help enforce immutability. With positional parameters, you can declare a model in just a line of code. Check this out:</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.MapGet("/person", () =&gt; new Person("Bill", "Gates"));
await app.RunAsync();

public record Person(string FirstName, string LastName);</code></pre><p>In this case, the model binding is handled for us, as we get this response back:</p><pre><code>HTTP/1.1 200 OK
Connection: close
Date: Fri, 04 Jun 2021 11:36:31 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

{
  "firstName": "Bill",
  "lastName": "Gates"
}</code></pre><p>As we get closer to the .NET 6 release, this will likely work with annotations as well, like if I wanted to make my <code>LastName</code> required:</p><pre><code class="language-csharp">public record Person(string FirstName, [Required] string LastName);</code></pre><p>So far, we haven't passed anything to our inline lambdas. If we set a <code>POST</code> endpoint, we can pass in the <code>Person</code> and output what was passed in. (Of course, a more common ideal real-world scenario would be passing in a database context. I'll leave that as an exercise for you, as setting up a database and initializing data is outside the scope of this post.)</p><pre><code class="language-csharp">var app = WebApplication.Create(args);
app.MapPost("/person", (Person p) =&gt; $"We have a new person: {p.FirstName}     {p.LastName}");
await app.RunAsync();

public record Person(string FirstName, string LastName);</code></pre><p>When I use a tool such as Fiddler (wink, wink), I'll get the following response:</p><pre><code>HTTP/1.1 200 OK
Connection: close
Date: Fri, 04 Jun 2021 11:36:31 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

We have a new person: Ron Swanson</code></pre><h2 id="use-middleware-and-dependency-injection-with-minimal-apis">Use middleware and dependency injection with Minimal APIs</h2><p>Your production-grade APIs—no offense, Ron Swanson—will need to deal with dependencies and middleware. You can handle this all through your <code>Program.cs</code> file, as there is no <code>Startup</code> file out of the box. When you create a <code>WebApplicationBuilder</code>, you have access to the trusty <code>IServiceCollection</code> to register your services. </p><p>Here's a common example, when you want only to show exception details when developing locally. </p><pre><code class="language-csharp">var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

// endpoints</code></pre><p>There's nothing against you creating a <code>Startup</code> file yourself as you always have, but you can do it right here in <code>Program.cs</code> as well.</p><h2 id="try-out-minimal-apis-yourself">Try Out Minimal APIs Yourself</h2><p>If you'd like to try out Minimal APIs yourself right now, you have two choices: live on the edge or live on the bleeding edge.</p><h3 id="live-on-the-edge-using-the-preview-bits">Live On The Edge: Using the Preview Bits</h3><p>Starting with Preview 4, you can use that release to explore how Minimal APIs work, with a couple of caveats:</p><ul><li>You can't use global usings</li><li>The lambdas will be casted</li></ul><p>Both of these are resolved with C# 10, but the Preview 4 bits use C# 9 for now. If you want to use Preview 4, install <a href="https://dotnet.microsoft.com/download/dotnet/6.0?ref=daveabrock.com">the latest .NET 6 SDK</a>—I'd also recommend installing <a href="http://visualstudio.com/preview?ref=daveabrock.com">the latest Visual Studio 2019 Preview</a>. Here's how our first example would look. (I know, six lines of code. What a drag.)</p><pre><code class="language-csharp">using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;

var app = WebApplication.Create(args);
app.MapGet("/", (Func&lt;string&gt;)(() =&gt; "Hello World!"));
await app.RunAsync();</code></pre><p>If you want to start with an app of your own, you can execute the following from your favorite terminal:</p><pre><code class="language-bash">dotnet new web -o MyMinimalApi</code></pre><h3 id="living-on-the-bleeding-edge-use-c-10-and-the-latest-compiler-tools">Living on the Bleeding Edge: Use C# 10 and the latest compiler tools</h3><p>If you want to live on the bleeding edge, you can use the latest compiler tools and C# 10. </p><p>First, you'll need to add a custom <code>nuget.config</code> to the root of your project to get the latest tools:</p><pre><code class="language-xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;configuration&gt;
  &lt;packageSources&gt;
    &lt;!--To inherit the global NuGet package sources remove the &lt;clear/&gt; line below --&gt;
    &lt;clear /&gt;
    &lt;add key="nuget" value="https://api.nuget.org/v3/index.json" /&gt;
    &lt;add key="dotnet6" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet6/nuget/v3/index.json" /&gt;
    &lt;add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" /&gt;
  &lt;/packageSources&gt;
&lt;/configuration&gt;</code></pre><p>In your project file, add the following to use the latest compiler tools and enable the capability for the project to read your global usings from a <code>.usings</code> file:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
   &lt;PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="4.0.0-2.21275.18"&gt;
      &lt;PrivateAssets&gt;all&lt;/PrivateAssets&gt;
      &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/IncludeAssets&gt;
   &lt;/PackageReference&gt;
&lt;/ItemGroup&gt;

&lt;ItemGroup&gt;
  &lt;Compile Include=".usings" /&gt;
&lt;/ItemGroup&gt;</code></pre><p>Then, you can create and update a <code>.usings</code> file, and you are good to go! I owe a debt of gratitude to <a href="https://twitter.com/buhakmeh?ref=daveabrock.com">Khalid Abuhakmeh</a> and <a href="https://github.com/khalidabuhakmeh/CsharpTenFeatures?ref=daveabrock.com">his CsharpTenFeatures repo</a> for assistance. Feel free to refer to that project if you have issues getting the latest tools.</p><h2 id="what-does-this-mean-for-apis-in-aspnet-core">What does this mean for APIs in ASP.NET Core?</h2><p>If you're new to building APIs in ASP.NET Core, this is likely a welcome improvement. You can worry about building APIs and not all the overhead that comes with MVC.</p><p>If you've developed ASP.NET Core APIs for a while, like me, you may be greeting this with both excitement and skepticism. This is great, but does it fit the needs of a production-scale API? And when it does, will it be hard to move over to the robust capabilities of ASP.NET Core MVC?</p><p>With Minimal APIs, the goal is to move out core API building capabilities—the ones that <em>only </em>exist in MVC today—and allow them to be used outside of MVC. When extracting these components away to a new paradigm, you can rely on middleware-like performance. Then, if you need to move from inline lambdas to MVC and its classes and controllers, the ASP.NET team plans to provide a smooth migration for you. These are two different roads with a bridge between them.</p><p>If you think long-term, Minimal APIs could be the default way to build APIs in ASP.NET Core—in most cases, it's better to start off small and then grow, rather than starting with MVC and not leveraging all its capabilities. Once you need it, it'll be there.</p><p>Of course, we've only scratched the service in all you can do with Minimal APIs. I'm interested in what you've built with them. What are your thoughts? Leave a comment below.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #52: 🎂 Happy birthday to us ]]></title>
        <description><![CDATA[ In this extended issue, we&#39;re recapping Build and walking through the release of .NET 6 Preview 4. ]]></description>
        <link>https://www.daveabrock.com/2021/05/31/dotnet-stacks-52/</link>
        <guid isPermaLink="false">60b23fb4941321003e21ba22</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 31 May 2021 18:44:41 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/dotnet-stacks-birthday.png" medium="image"/>
        <content:encoded><![CDATA[ <p>As if the completely ridiculous banner image didn't tip it off, it's true: today is the 1st birthday of <em>The .NET Stacks</em>! I'd like to thank <a href="https://www.daveabrock.com/2020/06/13/dev-discussions-isaac-levin/">our friend Isaac Levin</a>—our first interview guest—for being such a good sport. If you haven't seen the <a href="https://www.youtube.com/watch?v=EWYYgEkGJfs&ref=daveabrock.com">wonderful "Application Development" keynote from Build</a>, you should (and the picture will all make sense). </p><p>But most of all, I'd like to thank all of you for your support. Honestly, this little project started as a way to keep my mind busy during a pandemic lockdown and I really wasn't sure how things would go. (Looking back <a href="https://www.daveabrock.com/2020/05/24/dotnet-stacks-1/">at the first issue</a> ... that was very evident.) I'm thrilled it's been able to have the impact it has, and I'm grateful to all of you for that.</p><p>With all that out of the way, what are we talking about this week? In this extended issue, there's a<em> lot</em> here:  </p><ul><li>Build 2021 recap</li><li>.NET 6 Preview 4 has arrived</li><li>Visual Studio updates</li><li>System.Console in .NET 7</li></ul><hr><h2 id="build-2021-recap">Build 2021 recap</h2><p>Last week, Microsoft rolled out Build 2021. You can check out the 330 sessions <a href="https://mybuild.microsoft.com/sessions?ref=daveabrock.com">at the Build website</a>, and there's a YouTube playlist at the <a href="https://www.youtube.com/watch?v=KQt0v950h6k&list=PLlrxD0HtieHgMGEnTzEEfkADbaG8aAWRp&ref=daveabrock.com">Microsoft Developer YouTube channel</a>. It's no secret that these days Build is heavy on promoting Azure services, but .NET got a lot of love last week, too.</p><p>Your mileage may vary, but my favorite sessions included the <a href="https://www.youtube.com/watch?v=EWYYgEkGJfs&ab_channel=MicrosoftDeveloper&ref=daveabrock.com">application development keynote</a>, a <a href="https://www.youtube.com/watch?v=SMz_QDZYZCw&ref=daveabrock.com">.NET "Ask the Experts" session</a>,  <a href="http://www.youtube.com/watch?v=Ok-csh6FLL0&ref=daveabrock.com">increasing productivity with Visual Studio</a>, <a href="http://www.youtube.com/watch?v=DyKYB76SDx0&ref=daveabrock.com">microservices with Dapr</a>, <a href="https://www.youtube.com/watch?v=2Ky28Et3gy0&ref=daveabrock.com">modern app development with .NET</a>, and a .NET 6 <a href="https://www.youtube.com/watch?v=GJ_PaRNDe9E&ref=daveabrock.com">deep-dive session with Scott Hunter</a>. (Hunter is Microsoft's CSO—the Chief Scott Officer. He also runs .NET.)</p><p>I want to call out a few interesting details from that session: updates on C# 10 and a new Blazor FluentUI component library that's taking shape. (There were other nice updates on .NET MAUI and Minimal APIs that we'll surely address in depth in later issues.)</p><h3 id="c-10-updates">C# 10 updates</h3><p>In Scott Hunter's talk, Mads Torgersen and Dustin Campbell walked through some updates coming to C# 10. C# 10 looks to be focused on productivity and simplicity features. I want to show off record structs, required object initializers, auto-implemented property improvements, null parameter checking, global usings, and file-scoped namespaces.</p><h4 id="record-structs">Record structs</h4><p>C# 9 <a href="https://www.daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records/">brought us records</a>, which gives you the ability to enforce immutability with the benefits of "value-like" behavior. While the C# 9 records are really just a class under the covers and accessed by reference, the "value-like" behaviors ensure that default equality checking works with your object's data (as opposed to reference equality). A good use case is with DTOs and other objects that benefit from immutability.</p><p>With all reference types, though, passing around a lot of records can create a lot of pressure on the garbage collector. If you couple that with using <code>with</code> expressions, copying and GC pressure <a href="https://twitter.com/MadsTorgersen/status/1327033065168748545?ref=daveabrock.com">can become an issue</a> if you go crazy with records. Can we use structs with records? With C# 10, you can with the <code>record struct</code> syntax. It'll behave similarly, with the only key difference being that record structs aren't heap-allocated. This will also work with tuples, expressions, or any other struct types. </p><p>Let's look at some code, shall we? Let's say you have a <code>Person</code> record in C# 9:</p><pre><code class="language-csharp">record Person
{
   public string FirstName { get; init; }
   public string LastName { get; init; }
}</code></pre><p>To use a record struct, change it to this:</p><pre><code class="language-csharp">record struct Person
{
   public string FirstName { get; init; }
   public string LastName { get; init; }
}</code></pre><p>The default <code>record</code> declaration will still be a reference type. If you want to make that explicit, you can use the new <code>class struct</code> syntax. They are the same.</p><h4 id="required-object-initializers">Required object initializers</h4><p>I enjoy the flexibility of object initializers. You can use them to initialize objects however you want: you can initialize just a few properties, in whatever order you want, or none at all! Unfortunately, this flexibility can also bite you in the rear end if you aren't careful.</p><p>With C# 10, you can set fields to be required when performing object initialization, like this:</p><pre><code class="language-csharp">record struct Person
{
   public required string FirstName { get; init; }
   public required string LastName { get; init; }
}</code></pre><p>Its early days on this feature, but it might also help to enforce whether types can be instantiated by positional syntax (constructors) or object initialization.</p><h4 id="auto-implemented-property-improvements">Auto-implemented property improvements</h4><p>In the Build talk, Dustin and Mads talked about <em>the cliff</em>: let's say you want to change one little thing about an auto-implemented property. The next thing you know, you're creating a backing field, adding bodies for your getters and setters, and you're left wondering why it takes so much work to change one little thing.</p><p>With C# 10, you can refer to the auto-generated backing field without all that nonsense. You'll be able to work with a <code>field</code> keyword in your getters, setters, or even both. </p><pre><code class="language-csharp">record struct Person
{
   public string FirstName { get; init =&gt; field = value.Trim(); }
   public string LastName { get; init; }
}</code></pre><p>This change provides better encapsulation and fewer lines of boilerplate code.</p><h4 id="null-parameter-checks">Null parameter checks</h4><p>We've seen many nullability improvements over the last few C# releases, but null parameter checking can still be a manual chore—even with null reference types, you have to depend on the caller to do null checks. </p><p>With C# 10, this is taken care of with the <code>!!</code> keyword:</p><pre><code class="language-csharp">public void DoAThing(string text!!)
{
   Console.WriteLine(text);
}</code></pre><p>Don't worry, you aren't seeing double—this doesn't mean you're super excited about the <code>text</code> argument. Personally, I'm not a fan of the <code>!!</code>—at this rate, the C# team will need to start inventing new characters—but I <em>am</em> a fan of removing a bunch of this boilerplate nonsense. </p><h4 id="global-usings-and-file-based-namespaces">Global usings and file-based namespaces</h4><p>Lastly, the team introduced a few enhancements to help simplify your C# codebase.</p><p>With global usings, you can use the <code>global using</code> keywords to signify usings should be accessible throughout every <em>.cs</em> file in your project.</p><p>Here's a typical example of using statements you might want to use in your global using file: </p><pre><code class="language-csharp">global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
global using static System.Console;</code></pre><p>I wonder if we could use Roslyn analyzers to shake out unused global usings for individual files. Anyway, I think this is a feature I will originally hate, then learn to love. It's nice to see what is being used, but after a while, it's a maintenance headache. This will be nice. (Not to mention ASP.NET Core developers are familiar with a similar approach with Razor files.) In any case, in many files, you might wind up with a global usings file, then individual usings for references that aren't scattered across your projects.</p><p> Lastly, the team introduced file-scoped namespaces. It allows you to go from this:</p><pre><code class="language-csharp">namespace MyNamespace
{
   record Person
   {
      public string FirstName { get; init; }
      public string LastName { get; init; }
   }
}</code></pre><p>To this:</p><pre><code class="language-csharp">namespace MyNamespace;

record Person
{
   public string FirstName { get; init; }
   public string LastName { get; init; }
}</code></pre><p>Of course, you could use top-level statements to remove namespaces completely—however, there are plenty of reasons why you don't want to abstract away your namespace declarations. In those cases, it's a nice, clean approach.</p><h3 id="new-blazor-component-library">New Blazor component library</h3><p>So here's something interesting that isn't getting a lot of attention: Microsoft is <a href="https://github.com/microsoft/fast-blazor?ref=daveabrock.com">working on a component library for Blazor</a>. Technically, these are wrappers around Microsoft's existing FluentUI Web Components and are <a href="https://www.fast.design/?ref=daveabrock.com">built on FAST</a>. You can fork the repository and browse to the <em>examples </em>app for a test page:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/fast-components.jpg" class="kg-image" alt loading="lazy" width="1095" height="1025" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/fast-components.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/fast-components.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/fast-components.jpg 1095w" sizes="(min-width: 720px) 720px"></figure><p>This is early, but I'd recommend taking a look—while it comes with the Blazor name, these are technically Razor components. This means you use them in other ASP.NET Core web apps, such as Razor Pages and MVC. </p><p>Microsoft customers have been asking for an in-house, free component library for a while—this will fill the need. While Microsoft will eventually introduce this as yet another tool at your disposal, they'll need to be careful here: the .NET community has a rich community of open-source and third-party component libraries (both free and paid), and they'll need to avoid the perception they're trying to replace these options. (To be abundantly clear, they definitely are not.)</p><hr><h2 id="net-6-preview-4-has-arrived">.NET 6 Preview 4 has arrived</h2><p>Just minutes into Build, Microsoft announced the official release of .NET 6 Preview 4. We've teased a few features in the last month or so, but it's nice to see the official news. Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com">wrote up the blog post</a>. As a reminder, .NET 6 will be an LTS release.</p><p><a href="https://devblogs.microsoft.com/dotnet/introducing-net-hot-reload/?ref=daveabrock.com">.NET Hot Reload</a> is a big .NET 6 feature (as is improving the developer inner loop in general). I've <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">written about</a> how you can use it by running <code>dotnet watch</code> with ASP.NET Core web apps (that is, Blazor, Razor Pages, and MVC). With Preview 4, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#tools-hot-reload-with-the-visual-studio-debugger-and-dotnet-cli">you can also use it</a> with other project types like WPF, Windows Forms, WinUI, console apps and "other frameworks that are running on top of the CoreCLR runtime." It's now integrated with the Visual Studio debugger as well—to do this, you need to download VS 2019 16.11 Preview 1.</p><p>In Lander's post, we also see much of what we've discussed previously: check out the official details on <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#system-text-json-support-for-iasyncenumerable"><code>System.Text.Json</code> improvements</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#system-linq-enhancements">LINQ enhancements</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#significantly-improved-filestream-performance-on-windows">FileStream performance improvements on Windows</a>, and <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/?ref=daveabrock.com#enhanced-date-time-and-time-zone-support">new <code>DateOnly</code> and <code>TimeOnly</code> structs</a>.</p><p>What about ASP.NET Core? ASP.NET Core is bringing it in this release—there's <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#introducing-minimal-apis">Minimal APIs</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#async-streaming">async streaming</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#http-logging-middleware">HTTP logging middleware</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#improved-single-page-app-spa-templates">improved SPA templates</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-error-boundaries">Blazor error boundaries</a>, and ... drum roll ... <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-webassembly-ahead-of-time-aot-compilation">Blazor WebAssembly ahead-of-time (AOT) compilation</a>! You can also start building <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/?ref=daveabrock.com#blazor-webassembly-ahead-of-time-aot-compilation">.NET MAUI client-side apps with Blazor</a>. Speaking of MAUI, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-4/?ref=daveabrock.com">there's a separate post outlining its Preview 4 updates</a>. If you're using Entity Framework, make sure to check out that team's Preview 4 post <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-4-performance-edition/?ref=daveabrock.com">to see all the wonderful perf improvements</a>.</p><p>Preview 4 is a big one. Even with a little under six months to go, we'll only have a few previews to go until the focus turns to bug fixes. .NET 6 is coming along nicely. </p><hr><h2 id="visual-studio-updates">Visual Studio updates</h2><p>Last week, Microsoft also released <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com">Visual Studio 2019 v16.10 and v16.11 Preview 1</a>. </p><p>With 16.10, we're seeing some more <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com">Git workflow improvements</a>. The initial improvements to Git workflow in Visual Studio 2019 were a little rough, if we're being honest. It's nice to see the Visual Studio team listening to customer feedback and making it better. You can also now <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com">remove unused references</a>—a long-adored ReSharper feature. In other news, there's <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com#containers">improvements to Docker container tooling</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com#containers">IntelliSense completion improvements</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com#test-explorer-accessibility-improvements">Test Explorer improvements</a>, and more. If F# is your jam, Phillip Carter <a href="https://devblogs.microsoft.com/dotnet/f-and-f-tools-update-for-visual-studio-16-10/?ref=daveabrock.com">announced some tooling updates for 16.10</a>.</p><p>Also, if you're developing Azure Functions with the isolated worker in .NET 5, Azure Functions PM Anthony Chu has an update for you:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">If you&#39;re building .NET 5 isolated <a href="https://twitter.com/AzureFunctions?ref_src=twsrc%5Etfw&ref=daveabrock.com">@AzureFunctions</a> apps and want to use <a href="https://twitter.com/VisualStudio?ref_src=twsrc%5Etfw&ref=daveabrock.com">@VisualStudio</a>, update to VS 2019 v16.10 for full support for templates, local debug, and deployment.<br><br>We&#39;ll be updating our tutorial and docs shortly. <a href="https://t.co/eaGjTdr9mp?ref=daveabrock.com">pic.twitter.com/eaGjTdr9mp</a></p>&mdash; Anthony Chu (@nthonyChu) <a href="https://twitter.com/nthonyChu/status/1397621201191665666?ref_src=twsrc%5Etfw&ref=daveabrock.com">May 26, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>With 16.11 Preview 1, the big news is supporting <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com#net-hot-reload">hot reload in Visual Studio</a>. We're <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today/?ref=daveabrock.com#net-hot-reload">also seeing .NET MAUI support</a>.</p><p>On the topic of IDEs,  JetBrains released its roadmaps for <a href="https://blog.jetbrains.com/dotnet/2021/05/25/resharper-2021-2-roadmap/?ref=daveabrock.com">ReSharper 2021.2</a> and <a href="https://blog.jetbrains.com/dotnet/2021/05/26/rider-2021-2-roadmap/?ref=daveabrock.com">Rider 2021.2</a>.</p><hr><h2 id="rethinking-systemconsole-in-net-7">Rethinking System.Console in .NET 7</h2><p>With .NET 7—yes, .NET 7!—Microsoft is taking a look at redesigning <code>System.Console</code>.</p><p>As <a href="https://github.com/dotnet/runtime/issues/52374?ref=daveabrock.com#issue-877319518">Adam Sitnik describes it</a>, the initial design was driven by Windows OS capabilities and APIs. With .NET going cross-platform, it introduced a number of issues since there wasn't a good way to map Windows concepts to Unix. You're encouraged to <a href="https://github.com/dotnet/runtime/issues/52374?ref=daveabrock.com">follow the discussion and provide feedback</a>.</p><p>We've seen a lot of community innovation in this space. For example, Patrik Svensson's <a href="https://github.com/spectreconsole/spectre.console?ref=daveabrock.com">Spectre.Console library</a> shows us that the developer console experience can be productive <em>and </em>beautiful. This <a href="https://github.com/dotnet/runtime/issues/52374?ref=daveabrock.com#issuecomment-834159352">isn't lost</a> and I'm interested to see how this work evolves.  </p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p>Welcome to Build week, where announcements are everywhere.</p><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Microsoft Build 2021 came and went—<a href="https://blogs.microsoft.com/blog/2021/05/24/from-developers-to-inspired-creators/?ref=daveabrock.com" rel="nofollow">Amanda Silver</a> and <a href="https://blogs.microsoft.com/blog/2021/05/25/microsoft-loves-developers-welcome-to-build-2021/?ref=daveabrock.com" rel="nofollow">Scott Guthrie</a> welcome you, and Microsoft <a href="https://news.microsoft.com/build-2021-book-of-news/?ref=daveabrock.com" rel="nofollow">provides the Build 2021 Book of News</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4?ref=daveabrock.com" rel="nofollow">announces .NET 6 Preview 4</a>, Dan Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4?ref=daveabrock.com" rel="nofollow">announces ASP.NET Core updates</a>, Shay Rojansky <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-4-performance-edition?ref=daveabrock.com" rel="nofollow">does the same for EF Core</a>, and David Ortinau <a href="https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-4?ref=daveabrock.com" rel="nofollow">announces .NET MAUI Preview 4</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/05/25/resharper-2021-2-roadmap/?ref=daveabrock.com" rel="nofollow">announces the roadmap for ReSharper 2021.2</a> and also for <a href="https://blog.jetbrains.com/dotnet/2021/05/26/rider-2021-2-roadmap/?ref=daveabrock.com" rel="nofollow">Rider 2021.2</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Microsoft <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-and-v16-11-preview-1-are-available-today?ref=daveabrock.com" rel="nofollow">releases Visual Studio 2019 v16.10 and v16.11 Preview 1</a>, and Phillip Carter <a href="https://devblogs.microsoft.com/dotnet/f-and-f-tools-update-for-visual-studio-16-10?ref=daveabrock.com" rel="nofollow">announces F# and F# tools updates</a>.</li><li>Dmitry Lyalin <a href="https://devblogs.microsoft.com/dotnet/introducing-net-hot-reload?ref=daveabrock.com" rel="nofollow">introduces the .NET Hot Reload experience for editing code at runtime</a>.</li><li>The Windows Package Manager <a href="https://devblogs.microsoft.com/commandline/windows-package-manager-1-0?ref=daveabrock.com" rel="nofollow">goes 1.0</a>, and Kayla Cinnamon <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-9-release?ref=daveabrock.com" rel="nofollow">releases Windows Terminal Preview 1.9</a>.</li><li>Troy Hunt <a href="https://www.troyhunt.com/pwned-passwords-open-source-in-the-dot-net-foundation-and-working-with-the-fbi/?ref=daveabrock.com" rel="nofollow">announces that Have I Been Pwned is part of the .NET Foundation and a partnership with the FBI</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/aloha-from-telerik-ui-for-maui?ref=daveabrock.com" rel="nofollow">announces Telerik UI for MAUI</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/05/24/vs-2022-roadmap.aspx?ref=daveabrock.com" rel="nofollow">writes about the Visual Studio 2022 roadmap</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=jLJVMD2GBAA&ref=daveabrock.com">talks to Christos Matskas about Microsoft Identity</a>.</li><li>Wolfgang Hennerbichler <a href="https://github.blog/2021-05-26-why-and-how-github-is-adopting-opentelemetry/?ref=daveabrock.com" rel="nofollow">writes about how GitHub is adopting OpenTelemetry</a>.</li><li>Because of Build, no community standups.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>The Code Maze blog <a href="https://code-maze.com/structured-logging-in-asp-net-core-with-serilog/?ref=daveabrock.com" rel="nofollow">uses Serilog with ASP.NET Core</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/blazor/2021/05/21/Blazor-and-SignalR.html?ref=daveabrock.com" rel="nofollow">uses Blazor with SignalR</a>.</li><li>Matthew Groves <a href="https://blog.couchbase.com/sql-nosql-comparison-aspnet-application/?ref=daveabrock.com" rel="nofollow">compares SQL and NoSQL in ASP.NET</a>.</li><li>Jeremy Likness <a href="https://www.grapecity.com/blogs/10-blazor-features-you-probably-didnt-know?ref=daveabrock.com" rel="nofollow">writes about 10 Blazor features you might not know about</a>.</li><li>Jay Krishna Reddy <a href="https://www.c-sharpcorner.com/article/odata-in-net-5/?ref=daveabrock.com" rel="nofollow">writes about using OData in .NET 5</a>.</li><li>Mark Downie <a href="https://www.poppastring.com/blog/disable-floc-in-aspnet?ref=daveabrock.com" rel="nofollow">disables FLoC in ASP.NET</a>.</li><li>Joydip Kanjilal <a href="https://auth0.com/blog/implementing-nanoservices-in-aspnet-core/?ref=daveabrock.com" rel="nofollow">implements nanoservices in ASP.NET Core</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/simple-example-of-calling-rest-api-with-httpclient-in-net5.0?ref=daveabrock.com" rel="nofollow">calls a REST API with HttpClient in .NET 5.0</a>.</li><li>David McCarter <a href="https://www.c-sharpcorner.com/article/architecture-processing-data-with-microservices/?ref=daveabrock.com" rel="nofollow">processes data with microservices</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Patrick Smacchia <a href="https://blog.ndepend.com/migrating-delegate-begininvoke-calls-to-net-core-net-5-and-net-6/?ref=daveabrock.com" rel="nofollow">migrates Delegate.BeginInvoke Calls to .NET Core, .NET 5 and .NET 6</a>.</li><li>Maarten Balliauw <a href="https://blog.maartenballiauw.be/post/2021/05/25/running-a-net-application-as-a-service-on-linux-with-systemd.html?ref=daveabrock.com" rel="nofollow">runs a .NET application as a service on Linux with Systemd</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/using-dateonly-and-timeonly-in-dotnet-6?ref=daveabrock.com" rel="nofollow">uses DateOnly and TimeOnly in .NET 6</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/05/27/build-win-dev.aspx?ref=daveabrock.com" rel="nofollow">provides updates on Project Reunion</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/the-difference-between-html-and-url-encode-in-dotnet?ref=daveabrock.com" rel="nofollow">explains the difference between HTML and URL Encode in .NET</a>.</li><li>Paula Fahmy <a href="https://dev.to/paulafahmy/asynchronous-c-making-a-simple-cup-of-tea-13i?ref=daveabrock.com" rel="nofollow">begins a series on async C#</a>.</li><li>Jonathan Allen <a href="https://www.infoq.com/articles/CSharp-Source-Generator?ref=daveabrock.com" rel="nofollow">builds a source generator in C#</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Auth0-Actions-With-Azure-Function-App/?ref=daveabrock.com" rel="nofollow">uses Auth0 Actions with Azure Functions</a>.</li><li>Aaron Powell <a href="https://dev.to/azure/leveling-up-static-web-apps-with-the-cli-5g5h?ref=daveabrock.com" rel="nofollow">works with the Azure Static Web Apps CLI</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/how-to-stop-visual-studio-from-creating-launchsettings-json/?ref=daveabrock.com" rel="nofollow">stops Visual Studio from creating launchsettings.json</a>.</li><li>Steve Smith <a href="https://ardalis.com/vs-code-disable-logging-loading-symbols/?ref=daveabrock.com" rel="nofollow">disables logging loading symbols in VS Code</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Mark Allibone <a href="https://mallibone.com/post/xamarin-oidc-refresh?ref=daveabrock.com" rel="nofollow">uses the OIDC client in Xamarin Forms to refresh an access token</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-9?ref=daveabrock.com" rel="nofollow">provides his weekly MAUI update</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1741&ref=daveabrock.com" rel="nofollow">talks to Scott Hunter about Build 2021 announcements</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/youve-been-blazored-net-070/?ref=daveabrock.com" rel="nofollow">talks to Chris Sainty about Blazor</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/david-ortinau-on-multi-platform-app-development-using-net-maui-episode-142?ref=daveabrock.com" rel="nofollow">talks to David Ortinau about MAUI</a>.</li><li>The Coding Blocks Podcast <a href="https://www.codingblocks.net/podcast/some-fun-apis/?ref=daveabrock.com" rel="nofollow">talks through some fun APIs</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-197-net-data-with-jeremy-likness/?ref=daveabrock.com" rel="nofollow">talks about .NET Data with Jeremy Likness</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Azure-Cosmos-DB-update-MongoDB-40-notebooks-and-continuous-backup?ref=daveabrock.com" rel="nofollow">provides an update on Azure Cosmos DB</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Clustering-in-Orleans?ref=daveabrock.com" rel="nofollow">talks about clustering in Orleans</a> and also <a href="https://www.youtube.com/watch?v=l3ynBm6X_IM&t=49s&ref=daveabrock.com">C# exception filters</a>.</li><li>One Dev Question asks: <a href="https://channel9.msdn.com/Blogs/One-Dev-Minute/Who-at-Microsoft-is-using-WinUI--One-Dev-Question?ref=daveabrock.com" rel="nofollow">who at Microsoft is using WinUI?</a></li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/Improving-Accessibility-with-Xamarin-Community-Toolkit?ref=daveabrock.com" rel="nofollow">improves accessibility with the Xamarin Community Toolkit</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #51: 👷‍♂️ The excitement is Build-ing ]]></title>
        <description><![CDATA[ This week, we get ready for Microsoft Build, talk more about .NET 6 Preview 4, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/05/29/dotnet-stacks-51/</link>
        <guid isPermaLink="false">60aa7cc34dc2e1003bc1b6e7</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 29 May 2021 07:25:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-42.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, released on May 24, 2021. To get the issues right away, subscribe at </em><a href="https://dotnetstacks.com/?ref=daveabrock.com"><em>dotnetstacks.com</em></a><em> or the bottom of this post.</em></p><p>Happy Monday! I hope you're all doing well. </p><p>Here's what's going on this week:</p><ul><li><strong>The big thing</strong>: Previewing the big week ahead</li><li><strong>The little things</strong>: SecureString meeting its demise, the .NET Coding Pack, web dev news</li><li>Last week in the .NET world</li></ul><hr><h2 id="the-big-thing-previewing-the-big-week-ahead">The big thing: Previewing the big week ahead</h2><p>This week will be a big one: we've got Microsoft Build—probably the last virtual one—which kicks off on Tuesday. In what is surely not coincidental timing, .NET 6 Preview 4 should also be released. (And if that isn't enough, <em>The .NET Stacks</em> turns 1 next Monday. Please, no gifts.)</p><p>While Build doesn't carry the same developer excitement as it has in the past, in my opinion—the frenetic pace of .NET keeps us busy throughout the year, and, to me, Build has shifted toward a marketing event. Still, it'll be nice to watch some sessions and see where things are going. You can check out the sessions <a href="https://mybuild.microsoft.com/home?ref=daveabrock.com">on the Build website</a>.  I'll be keeping an eye on <a href="https://mybuild.microsoft.com/sessions/70d379f4-1173-4941-b389-8796152ec7b8?source=sessions">a .NET 6 deep dive</a>, <a href="https://mybuild.microsoft.com/sessions/a5648d1d-b523-4549-a2bc-a0ad226cfe2a?source=sessions">microservices with Dapr</a>, and an Ask the Experts panel <a href="https://mybuild.microsoft.com/sessions/43aba346-543e-4180-9b70-fff940935906?source=sessions">with many Microsoft .NET folks</a>.</p><p>Next week, we'll also see the release of .NET 6 Preview 4 (finally!). While we'll pore over some of it next week when its formally communicated, <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com">the "what's new" GitHub issue</a> really filled up this week and has some exciting updates. </p><h3 id="new-linq-apis">New LINQ APIs</h3><p>.NET 6 Preview 4 will include <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-825157960">quite a few new LINQ APIs</a>.</p><h4 id="index-and-range-updates">Index and Range updates</h4><p>LINQ will now see Enumerable support for <code>Index</code> and <code>Range</code> parameters. The <code>Enumerable.ElementAt</code> method will accept indices from the end of the enumerable, like this:</p><pre><code class="language-csharp">Enumerable.Range(1, 10).ElementAt(^4); // returns 7</code></pre><p>Also, an <code>Enumerable.Take</code> overload will accept <code>Range</code> parameters, which allows you to slice enumerable sequences easily.</p><h4 id="maxby-and-minby">MaxBy and MinBy</h4><p>The new <code>MaxBy</code> and <code>MinBy</code> methods allow you to use a key selector to find a maximum or minimum method, like this (the example here is taken from the issue):</p><pre><code class="language-csharp">var people = new (string Name, int Age)[] { ("Tom", 20), ("Dick", 30), ("Harry", 40) };
people.MaxBy(person =&gt; person.Age); // ("Harry", 40)</code></pre><h4 id="chunk">Chunk</h4><p>A new <code>Chunk</code> method allows you to chunk elements into a fixed size, like this (again, taken from the issue):</p><pre><code class="language-csharp">IEnumerable&lt;int[]&gt; chunks = Enumerable.Range(0, 10).Chunk(size: 3); // { {0,1,2}, {3,4,5}, {6,7,8}, {9} }
</code></pre><h3 id="new-dateonly-and-timeonly-structs">New DateOnly and TimeOnly structs</h3><p>We talked about this in a past issue, but we'll see <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840815510">some new </a><code><a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840815510">DateOnly</a></code><a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840815510"> and </a><code><a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840815510">TimeOnly</a></code><a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840815510"> structs</a> that add to <code>DateTime</code> support and do not deprecate what already exists. They'll be in the <code>System</code> namespace, as the others are. For use cases, think of <code>DateOnly</code> for business days and birthdays and <code>TimeOnly</code> for things like recurring meetings and weekly business hours. </p><h3 id="writing-doms-with-systemtextjson">Writing DOMs with System.Text.Json</h3><p>So, this is fun: Preview 4 will bring us <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-840857013">the ability to use a writable DOM feature</a> with <code>System.Text.Json</code>. There's quite a few use cases here. A big one is when you want to modify a subset of a large tree efficiently. For example, you'll be able to navigate to a subsection of a large JSON tree and perform operations from that subsection. </p><p>There's a lot more with Preview 4. Check out <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com">the GitHub issue</a> for the full details. We'll cover more next week.</p><hr><h2 id="the-little-things-securestring-meeting-its-demise-the-net-coding-pack-general-web-dev-news">The little things: SecureString meeting its demise, the .NET Coding Pack, general web dev news</h2><p>The <code>SecureString</code> API <em>seems </em>great, it really does. It means well. It allows you to flag text as confidential and provide an extra layer of security. The main driver is to avoid using secrets as plain text in a process's memory. However, this doesn't translate to the OS, even on Windows. Except for .NET Framework, array contents are passed around unencrypted. It does have a shorter lifetime, so there's that—but it isn't that secure. It's easy to screw up and hard to get right.</p><p>The .NET team has been trying to phase out <code>SecureString</code> for awhile in favor of a more flexible <code>ShroudedBuffer&lt;T&gt;</code> type. This <a href="https://github.com/dotnet/designs/pull/147?ref=daveabrock.com#issuecomment-844392771">issue comment</a> has all the juicy details of the latest updates.</p><hr><p>This week, Scott Hanselman wrote about <a href="https://www.hanselman.com/blog/introducing-the-net-coding-pack-for-vs-code-getting-started-with-c-for-beginners?ref=daveabrock.com">the .NET Coding Pack for Visual Studio Code</a>. The pack includes an installation of VS Code, the .NET SDK (and adding it to the PATH), and a .NET extension. With the .NET Coding Pack, beginners will be able to work with .NET Interactive notebooks to quickly get started.</p><hr><p>While we mostly talk about .NET around here, I think it's important to reach outside our bubble and keep up with web trends. I came across two interesting developments last week.</p><p>Google has decided to no longer give Accelerated Mobile Pages (AMP) preferential treatment in its search results (and they are even <a href="https://plausible.io/blog/google-amp?ref=daveabrock.com">removing the icon</a> from the results page). Whatever the reason—its controversy, lack of adoption, or Google's anti-trust pressure—it's a welcome step for an independent web. (Now, <a href="https://www.cnet.com/news/google-may-be-resurrecting-google-reader-inside-chrome-with-follow-button/?ref=daveabrock.com">if only they'd bring back Google Reader</a>.)</p><p>In other news, StackBlitz—in cooperation with Google Chrome and Vercel—has launched WebContainers, <a href="https://blog.stackblitz.com/posts/introducing-webcontainers/?ref=daveabrock.com">a way to run Node.js natively in your browser</a>.  Simply put, it's providing an online IDE. Thanks to the strides WebAssembly has made in the past few years, it's paved a way for a WASM operating system.</p><p>Under the covers, it includes a virtualized network stack that maps to the browser's ServiceWorker API, which enables offline support. It provides a leg up over something like Codespaces or various REPL solutions, which typically need a server. I take exception <a href="https://blog.stackblitz.com/posts/introducing-webcontainers/?ref=daveabrock.com#what-about-code-spaces%2Fsandbox%2Frepls%2F...%3F">with StackBlitz saying</a> those solutions "provide a worse experience than your local machine in nearly every way" ... but if you do any JavaScript work, this is an exciting development (especially when dealing with JS's notoriously cumbersome tooling and setup demands).</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p></p><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Jeremy Likness <a href="https://blog.jeremylikness.com/blog/azure-cosmos-db-with-ef-core-on-blazor-server/?ref=daveabrock.com" rel="nofollow">works with Azure Cosmos DB, EF Core, and Blazor Server</a>.</li><li>Matthew MacDonald asks: <a href="https://medium.com/young-coder/the-future-web-will-canvas-rendering-replace-the-dom-847be872884c?ref=daveabrock.com" rel="nofollow">will Canvas rendering replace the DOM?</a></li><li>Eve Turzillo <a href="https://www.telerik.com/blogs/how-to-organize-and-modify-existing-http-https-requests?ref=daveabrock.com" rel="nofollow">organizes and modifies existing HTTP and HTTPS requests with Fiddler</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-may-2021-cumulative-update-preview?ref=daveabrock.com" rel="nofollow">discusses the .NET Framework Cumulative Update for May</a>.</li><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-may-2021?ref=daveabrock.com" rel="nofollow">recaps the May release</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/05/18/dotmemory-support-for-linux-process-dumps/?ref=daveabrock.com" rel="nofollow">writes about dotMemory support for Linux process dumps</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Microsoft Build <a href="https://mybuild.microsoft.com/home?ref=daveabrock.com">kicks off Tuesday</a>. David Ramel <a href="https://visualstudiomagazine.com/articles/2021/05/20/build-2021.aspx?ref=daveabrock.com" rel="nofollow">previews Build 2021</a>, and Richard Hay <a href="https://www.windowsobserver.com/2021/05/20/microsoft-build-2021-digital-swag-downloads/?ref=daveabrock.com" rel="nofollow">links to some digital swag</a>. Also, the Visual Studio team <a href="https://devblogs.microsoft.com/visualstudio/the-visual-studio-family-welcomes-you-at-microsoft-build-2021?ref=daveabrock.com" rel="nofollow">previews their Build sessions</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/05/19/wg-outreach-proposals?ref=daveabrock.com" rel="nofollow">Outreach Committee announces a new proposal process</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=Ll5yLL83W8M&ref=daveabrock.com">talks to Steve Gordon about ElasticSearch.NET</a>.</li><li>A busy week with community standups: ASP.NET <a href="https://www.youtube.com/watch?v=5ceTua82w4s&ref=daveabrock.com">talks about accessibility</a>, Entity Framework <a href="https://www.youtube.com/watch?v=4k3WzW2ZdXs&ref=daveabrock.com">builds modern apps with GraphQL</a>, and <a href="https://www.youtube.com/watch?v=FZGhYEwsJ9k&ref=daveabrock.com">.NET Tooling discusses container tools</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Tomasz Pęczek <a href="https://www.tpeczek.com/2021/05/receiving-json-objects-stream-ndjson-in.html?ref=daveabrock.com" rel="nofollow">receives JSON Objects Stream (NDJSON) in ASP.NET Core MVC</a>.</li><li>Paul DeVito <a href="https://wrapt.dev/blog/building-an-event-driven-dotnet-application-setting-up-masstransit-and-rabbitmq?ref=daveabrock.com" rel="nofollow">continues writing about building an event-driven .NET app</a>.</li><li>Anoop Kumar Sharma <a href="https://www.c-sharpcorner.com/article/cookie-authentication-in-asp-net-core/?ref=daveabrock.com" rel="nofollow">writes about cookie authentication in ASP.NET Core</a>.</li><li>StackBlitz introduces WebContainers, which provide <a href="https://blog.stackblitz.com/posts/introducing-webcontainers/?ref=daveabrock.com" rel="nofollow">the ability to run Node.js natively in your browser</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/defining-httpclient-test-requests-by-using-a-bundle?ref=daveabrock.com" rel="nofollow">defines HttpClient test requests by using a bundle</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/assembly-version-via-api-endpoint-routing?ref=daveabrock.com" rel="nofollow">exposes a .NET assembly version from API endpoint routing</a>.</li><li>Kirtesh Shah <a href="https://www.c-sharpcorner.com/article/introduction-to-asp-net-core-razor-pages/?ref=daveabrock.com" rel="nofollow">introduces ASP.NET Core Razor Pages</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/05/17/securing-multiple-identity-provider-oauth-bearer-tokens-in-an-asp-net-core-api/?ref=daveabrock.com" rel="nofollow">secures OAuth bearer tokens from multiple identity providers in ASP.NET Core</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/custom-user-message-extension-methods-in-csharp-and-dotnet-5-mvc/?ref=daveabrock.com" rel="nofollow">uses custom user message extension methods in C# and MVC</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Konrad Kokosa asks: <a href="https://tooslowexception.com/why-should-you-care-about-net-gc/?ref=daveabrock.com" rel="nofollow">why should you care about .NET GC?</a></li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/working-with-dotnet-console-host-lifetime-events?ref=daveabrock.com" rel="nofollow">works with .NET console host lifetime events</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-pgo?ref=daveabrock.com" rel="nofollow">writes about profile-guided optimization (PGO) in .NET 6</a>.</li><li>Nick Randolph <a href="https://www.infoq.com/articles/future-windows-other-platforms-development/?ref=daveabrock.com" rel="nofollow">writes about the future of Windows development</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Muhammed Saleem <a href="https://code-maze.com/creating-business-workflows-with-azure-logic-apps/?ref=daveabrock.com" rel="nofollow">creates business workflows with Azure Logic Apps</a>.</li><li>Abhijit Jana <a href="https://dailydotnettips.com/the-fastest-way-to-get-started-with-microsoft-azure/?ref=daveabrock.com" rel="nofollow">explains how </a>to get started with Azure quickly.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Lost-In-Azure-Cloud-Identity-Serie-Part5/?ref=daveabrock.com" rel="nofollow">continues his series on Azure Identity</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2021/05/15/azurite-and-table-storage-dev-container/?ref=daveabrock.com" rel="nofollow">uses Azurite and Table Storage in a dev container</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Georg Dangl <a href="https://blog.dangl.me/archive/updating-azure-app-service-on-linux-for-docker-via-webhooks-from-c/?ref=daveabrock.com" rel="nofollow">updates the Azure App Service on Linux for Docker with C# webhooks</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/May/15/Async-Await-with-the-Null-Propagator?ref=daveabrock.com" rel="nofollow">finds a gotcha with the C# null ? propagator when doing async/await</a>.</li><li>Munib Butt <a href="https://www.c-sharpcorner.com/article/using-azure-blob-storage-in-c-sharp/?ref=daveabrock.com" rel="nofollow">uses Azure Blob Storage in C#</a>.</li><li>Akash Mair <a href="https://www.compositional-it.com/news-blog/data-exploration-in-f/?ref=daveabrock.com" rel="nofollow">writes about data exploration in F#</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Abhijit Jana <a href="https://dailydotnettips.com/ci-cd-using-github-actions-workflow-directly-from-visual-studio/?ref=daveabrock.com" rel="nofollow">uses GitHub Actions from Visual Studio</a>.</li><li>Maarten Balliauw <a href="https://blog.jetbrains.com/dotnet/2021/05/20/rider-nuget-credential-provider-for-jetbrains-space-private-repositories/?ref=daveabrock.com" rel="nofollow">writes about the Rider NuGet Credential Provider for JetBrains Space private repos</a>.</li><li>Charles Flatt <a href="https://www.softwaremeadows.com/posts/git_commit_checkout_is_a_snapshot__not_a_delta/?ref=daveabrock.com" rel="nofollow">recaps the git commit/checkout process</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Dennis Martinez <a href="https://www.telerik.com/blogs/5-ways-to-speed-up-your-end-to-end-tests?ref=daveabrock.com" rel="nofollow">writes about 5 ways to speed up your end-to-end tests</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/how-to-bypass-recaptchas-in-selenium-ui-tests?ref=daveabrock.com" rel="nofollow">bypasses ReCaptcha's in Selenium UI tests</a>.</li><li>Scott Brady <a href="https://www.scottbrady91.com/c-sharp/aes-gcm-dotnet?ref=daveabrock.com" rel="nofollow">writes about authenticated encryption in .NET with AES-GCM</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/testing-your-domain-when-event-sourcing/?ref=daveabrock.com" rel="nofollow">talks about testing your domain when event sourcing</a>.</li><li>Christian Heilmann <a href="https://christianheilmann.com/2021/05/17/you-cant-automate-accessibility-testing/?ref=daveabrock.com" rel="nofollow">says you can't automate accessibility testing</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>Scott Hanselman <a href="https://www.hanselminutes.com/789/developers-and-security-with-rey-bango?ref=daveabrock.com" rel="nofollow">talks to Rey Bango about developers and security</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/jeremy-likness-on-working-with-data-on-net-episode-141?ref=daveabrock.com" rel="nofollow">talks to Jeremy Likness about working with data in .NET</a>.</li><li>The .NET Core Show <a href="https://dotnetcore.show/episode-76-dotnet-new3-with-sayed-hashimi/?ref=daveabrock.com" rel="nofollow">talks about dotnet new3 With Sayed Hashimi</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-196-net-6-preview-with-rich-lander/?ref=daveabrock.com" rel="nofollow">talks to Rich Lander about .NET 6 Preview</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Learn Live <a href="https://channel9.msdn.com/Shows/Learn-Live/Learn-Git-Episode-4-Visual-Studio-Code-and-GitHub?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com" rel="nofollow">continues learning about Git</a>.</li><li>The Let's Learn .NET series <a href="https://www.youtube.com/watch?v=ttxAYDMKtSs&ref=daveabrock.com">talks about building accessible apps</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #50: 🆕 What&#x27;s new with C# 10? ]]></title>
        <description><![CDATA[ This week we see what&#39;s coming with C# 10, talk about Azure Static Web Apps, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/05/23/dotnet-stacks-50/</link>
        <guid isPermaLink="false">609fc71f4dc2e1003bc1b635</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 23 May 2021 10:45:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-41.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, released on May 17, 2021. To get the issues right away, subscribe at </em><a href="https://dotnetstacks.com/?ref=daveabrock.com"><em>dotnetstacks.com</em></a><em> or the bottom of this post.</em></p><p>Happy Monday! I hope you have a good week. Here's what we have this week:</p><ul><li><strong>The big thing</strong>: Checking in on C# 10</li><li><strong>The little things</strong>: Azure Static Web Apps goes GA, JetBrains .NET days, .NET 6 FileStream improvements, JSON schema validation</li><li>Last week in the .NET world</li></ul><hr><h2 id="the-big-thing-checking-in-on-c-10">The big thing: Checking in on C# 10</h2><p>Last week, Ken Bonny wrote a post <a href="https://kenbonny.net/introducing-csharp-10?ref=daveabrock.com">highlighting some new C# 10 features</a>. Of course, it's still a little early, and not all of these changes might make it in. But if language designer Mads Torgersen talks about them publicly, there's a good probability they will.</p><p>Ever since Microsoft rolled out records with C# 9, the community has been asking for record struct types. With the C# 9 release of records, the <code>record</code> type is a reference type that enforces value-like behaviors. With C# 10, the team is rolling out a <code>record struct</code> variant that makes the underlying type a value type. So, with a record struct, values will be copied over instead of by reference. Also, on the topic of records, you'll be able to add operators to them.</p><p>Apart from this, Ken recaps what else is (probably) coming:</p><ul><li>Flagging properties of classes, structs, records, or record structs as <code>required</code></li><li> A new <code>field</code> keyword that can eliminate backing fields</li><li>Enabling a single file to enable namespace imports</li><li>Improvements with lambda attributes and lambda signature inference</li></ul><p>There's <a href="https://kenbonny.net/introducing-csharp-10?ref=daveabrock.com">a lot more with Ken's post</a>, with some good code examples. Make sure to check it out to see what's coming with C# 10.</p><hr><h2 id="the-little-things-azure-static-web-apps-goes-ga-jetbrains-net-days-net-6-filestream-improvements-json-schema-validation">The little things: Azure Static Web Apps goes GA, JetBrains .NET days, .NET 6 FileStream improvements, JSON schema validation</h2><p>This week, Azure Static Web Apps <a href="https://azure.microsoft.com/en-us/blog/develop-production-scale-modern-web-apps-quickly-with-azure-static-web-apps/?ref=daveabrock.com">became generally available</a> (and to answer everyone's #1 question, yes, apex domains are supported now). I've written about it exhaustively with my <a href="https://www.daveabrock.com/tag/blast-off-blazor/">Blast Off with Blazor blog series</a>. The gist is this: you integrate your front-end (with various JavaScript frameworks or the Blazor component library) with a backend powered by Azure Functions. </p><p>This week, I recapped <a href="https://www.daveabrock.com/2021/05/13/azure-static-web-apps-favorite-things/">my favorite things about Azure Static Web Apps</a>—some I knew previously and some I learned about this week. I'm most impressed with the local development story. When using an Azure Static Web Apps CLI, you can leverage a static site server, a proxy to your API endpoints, and a mock authentication and authorization server.</p><p>Azure Static Web Apps is now shipping with a Standard tier. For 9 USD/month, you can take advantage of a 99.95% SLA and a "bring your own Functions" model. I find the latter to be most valuable, especially when you want to leverage other Azure Functions triggers (by default, you can only use HTTP triggers with Azure Static Web Apps). </p><hr><p>JetBrains hosted their .NET Days conference this week (online, of course). JetBrains always hosts first-class community events, and this was no different. You can check out all the sessions on YouTube. </p><p>On Day 1, folks talked about <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=632s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=052xutD86uI&ref=daveabrock.com">C# source generators</a></a>, <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=5245s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=z2B8OruMT6s&ref=daveabrock.com">debugging .NET apps</a></a>, <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=9910s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=g8MYUfplpt8&ref=daveabrock.com">writing high-performance code</a></a>, <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=14436s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=NbkiKdHV0KQ&ref=daveabrock.com">Azure CosmosDB and React</a></a>, <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=18297s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=d8S9jh6Xj6Y&ref=daveabrock.com">gRPC in .NET</a></a>, <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=23050s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=P7y-OxeSkZ8&ref=daveabrock.com">GraphQL and Blazor</a></a>, and <a href="https://www.youtube.com/watch?v=bBpFpr-Votk&t=27611s&ref=daveabrock.com"><a href="https://www.youtube.com/watch?v=ltXWsuqg_mo&ref=daveabrock.com">using .NET and Dapper</a></a>.</p><p>On Day 2, we learned about <a href="https://www.youtube.com/watch?v=Iy6WS4mWlx4&ref=daveabrock.com">the 10 best C# features</a>, <a href="https://www.youtube.com/watch?v=q3Ies_XTo_s&ref=daveabrock.com">F#</a>, <a href="https://www.youtube.com/watch?v=VaeZW1RISAY&ref=daveabrock.com">legacy refactoring</a>, <a href="https://www.youtube.com/watch?v=h7uVMKPHGtM&ref=daveabrock.com">using null and void in .NET</a>, <a href="https://www.youtube.com/watch?v=4JHwBX_qQE0&ref=daveabrock.com">async and await best practices</a>, <a href="https://www.youtube.com/watch?v=KM27QGVwgas&ref=daveabrock.com">debugging with JetBrains Rider</a>, and <a href="https://www.youtube.com/watch?v=B14973mdD0g&ref=daveabrock.com">containerizing with Kubernetes</a>.</p><hr><p>I'm getting a little antsy about the <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com">release of .NET 6 Preview 4</a>. Since Preview 3 was shipped five weeks ago, and Microsoft aims for a new preview release every month or so, we'll see Preview 4 very soon. It'll be jam-packed with updates for minimal APIs, AOT support, and more.</p><p>We'll also see improvements to <code>FileStream</code>. The .NET team is rewriting the library, focusing on Windows (as <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-830154834">the Unix implementation, built 20 years later, was already fast</a>). With these changes, the team notes that when used with async I/O, it now never performs blocking work.</p><p>"Dave, shut up and show us the benchmarks!" OK, <a href="https://github.com/dotnet/core/issues/6098?ref=daveabrock.com#issuecomment-830154834">fine</a>:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/image-20.png" class="kg-image" alt loading="lazy" width="664" height="295" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/image-20.png 600w, https://www.daveabrock.com/content/images/2021/05/image-20.png 664w"></figure><p>Look at those allocations! In the example above, reading a 1 MB file is 2.5x faster, and writing is 5.5x faster.</p><hr><p>When it comes to serialization with .NET, you've got a few options: mostly, the tried-and-true <a href="https://github.com/JamesNK/Newtonsoft.Json?ref=daveabrock.com">Newtonsoft.Json</a> (which just surpassed a billion NuGet downloads) and the native System.Text.Json library. Unfortunately, with System.Text.Json, there's no easy way to perform JSON schema validation, and schema validation is <a href="https://www.newtonsoft.com/store/jsonschema?ref=daveabrock.com">a paid feature</a> with Newtonsoft.Json. (There are also quite a few third-party options for schema validation as well.)</p><p>This week, Matthew Adams <a href="https://endjin.com/blog/2021/05/csharp-serialization-with-system-text-json-schema.html?ref=daveabrock.com">wrote a wonderful post</a> on achieving schema validation with System.Text.Json. He used code generation to create .NET types that represent the structure of the schema (with strongly typed accessors for properties, array/list elements, and so on).</p><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p>This week, we learn more about Azure Static Web Apps, GitHub Actions, modular monoliths, and more.</p><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Derek Comartin <a href="https://codeopinion.com/problem-details-for-better-rest-http-api-errors/?ref=daveabrock.com" rel="nofollow">recaps using Problem Details in ASP.NET Core Web API</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/getting-started-with-github-actions-for-dotnet-developers?ref=daveabrock.com" rel="nofollow">introduces GitHub Actions for .NET developers</a> and <a href="https://www.stevejgordon.co.uk/string-manipulation-in-csharp-best-practices?ref=daveabrock.com" rel="nofollow">writes about string manipulation in C#</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/evolving-modular-monoliths-2-breaking-up-your-app-into-multiple-solutions/?ref=daveabrock.com" rel="nofollow">continues his series on evolving modular monoliths</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Microsoft announces <a href="https://azure.microsoft.com/en-us/blog/develop-production-scale-modern-web-apps-quickly-with-azure-static-web-apps?ref=daveabrock.com" rel="nofollow">the GA release of Azure Static Web Apps</a>.</li><li>Auth0 introduces <a href="https://auth0.com/blog/actions-now-generally-available/?ref=daveabrock.com" rel="nofollow">Auth0 Actions</a>.</li><li>Microsoft announces <a href="https://devblogs.microsoft.com/dotnet/net-framework-may-2021-security-and-quality-rollup-updates?ref=daveabrock.com" rel="nofollow">the May updates for the .NET Framework</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/05/12/introducing-the-mvvmgen-library/?ref=daveabrock.com" rel="nofollow">introduces a new MVVM library</a>.</li><li>InfoQ talks to <a href="https://www.infoq.com/articles/deep-diving-ef-core-jeremy-likness/?ref=daveabrock.com" rel="nofollow">Jeremy Likness about EF Core</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/05/10/mercury.aspx?ref=daveabrock.com" rel="nofollow">writes about Mercury, a "modern Visual Basic</a>."</li><li>For community standups: Languages &amp; Runtime <a href="https://www.youtube.com/watch?v=gdnnDeI2XKY&ref=daveabrock.com">talks about source generation</a>, and Machine Learning <a href="https://www.youtube.com/watch?v=qGzkuFQenQg&ref=daveabrock.com">differentiates between a data scientist and a data engineer</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=BeieWY95WuM&ref=daveabrock.com">discusses mobile accessibility</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/catching-all-the-requests-while-testing-with-httpclient?ref=daveabrock.com" rel="nofollow">tests HttpClient</a>.</li><li>Muhammed Saleem <a href="https://code-maze.com/azure-cosmos-db-with-asp-net-core-web-api/?ref=daveabrock.com" rel="nofollow">integrates Azure Cosmos DB with ASP.NET Core Web API</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/create-tic-tac-toe-blazor-webassembly-in-hour?ref=daveabrock.com" rel="nofollow">creates a tic-tac-toe game in Blazor</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/05/10/present-and-verify-verifiable-credentials-in-asp-net-core-using-decentralized-identities-and-mattr/?ref=daveabrock.com" rel="nofollow">presents and verifies verifiable credentials in ASP.NET Core using decentralized identities and MATTR</a>.</li><li>Burak Guzel <a href="https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039?ref=daveabrock.com" rel="nofollow">writes a primer on HTTP headers</a>.</li><li>Jason Beres <a href="https://azure.microsoft.com/en-us/blog/develop-production-scale-modern-web-apps-quickly-with-azure-static-web-apps?ref=daveabrock.com" rel="nofollow">compares Blazor to React</a>.</li><li>Calvin Allen <a href="https://www.codingwithcalvin.net/real-time-ui-updates-with-postgres-and-signalr/?ref=daveabrock.com">works on real-time updates with Postgres and SignalR</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Tomasz Pęczek <a href="https://www.tpeczek.com/2021/05/streaming-json-objects-ndjson-with.html?ref=daveabrock.com" rel="nofollow">streams JSON Objects (NDJSON) with HttpClient</a>.</li><li>Paul DeVito <a href="https://wrapt.dev/blog/building-an-event-driven-dotnet-application-the-fundamentals?ref=daveabrock.com" rel="nofollow">builds an event-driven .NET application</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/using-the-new-priorityqueue-from-net-6/?ref=daveabrock.com" rel="nofollow">uses the PriorityQueue in .NET 6</a>.</li><li>Ken Bonny <a href="https://kenbonny.net/introducing-csharp-10?ref=daveabrock.com" rel="nofollow">introduces C# 10</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Lost-In-Azure-Cloud-Identity-Serie-Part4/?ref=daveabrock.com" rel="nofollow">continues writing about Azure Identity</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2021/05/08/create-pipeline-with-azure-devops-api/?ref=daveabrock.com" rel="nofollow">creates a pipeline with the Azure DevOps API</a>.</li><li>Mark Heath <a href="https://markheath.net/post/azurite?ref=daveabrock.com" rel="nofollow">runs Durable Functions locally with Azurite</a>.</li><li>Dave Brock <a href="https://www.daveabrock.com/2021/05/13/azure-static-web-apps-favorite-things/" rel="nofollow">recaps his favorite things about Azure Static Web Apps</a>.</li><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-05-13-using-okta-with-static-web-apps/?ref=daveabrock.com" rel="nofollow">uses Okta with Azure Static Web Apps</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Jeff Fritz <a href="https://dev.to/dotnet/my-favorite-c-features-part-4-project-structure-454p?ref=daveabrock.com" rel="nofollow">writes about C# project structure</a>.</li><li>Sasha Mathews <a href="https://levelup.gitconnected.com/5-ways-to-improve-the-performance-of-c-code-for-free-c89188eba5da?ref=daveabrock.com" rel="nofollow">offers quick tips to improve C# performance</a>.</li><li>Matthew Adams <a href="https://endjin.com/blog/2021/05/csharp-serialization-with-system-text-json-schema.html?ref=daveabrock.com" rel="nofollow">works on C# serialization with JsonSchema and System.Text.Json</a>.</li><li>Kirtesh Shah <a href="https://www.c-sharpcorner.com/article/learn-about-pattern-matching-in-c-sharp/?ref=daveabrock.com" rel="nofollow">writes about C# pattern matching</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/solve-for-the-next-dayofweek-from-datetime?ref=daveabrock.com" rel="nofollow">solves for the next DayOfWeek from DateTime</a>.</li><li>Josef Ottosson <a href="https://josef.codes/transform-csharp-objects-to-a-flat-string-dictionary/?ref=daveabrock.com" rel="nofollow">transforms C# objects to a flat string dictionary</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/using-csharp-named-arguments-to-declutter-complex-tests/?ref=daveabrock.com" rel="nofollow">uses C# named arguments to handle complex tests</a>.</li><li>Brian Lagunas <a href="https://brianlagunas.com/c-async-yield-return-iasyncenumerable-will-change-your-life/?ref=daveabrock.com" rel="nofollow">walks through async yield return in C#</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/05/07/testing-tools.aspx?ref=daveabrock.com" rel="nofollow">recaps free testing tools for Visual Studio 2019</a>.</li><li>Abhijit Jana <a href="https://dailydotnettips.com/did-you-know-visual-studio-can-add-using-directive-automatically-on-paste/?ref=daveabrock.com" rel="nofollow">reminds us that Visual Studio can add using directives automatically on paste</a>.</li><li>Aaron Stannard <a href="https://petabridge.com/blog/akkadotnet-aspnetcore/?ref=daveabrock.com" rel="nofollow">writes about integrating Akka.NET with ASP.NET Core and SignalR</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/visual-studio-2022-64-bits-elements-of-history/?ref=daveabrock.com" rel="nofollow">writes about the impacts of 64-bit Visual Studio 2022</a>.</li><li>Steve Smith <a href="https://ardalis.com/github-fetch-upstream/?ref=daveabrock.com" rel="nofollow">fetches an upstream branch in GitHub</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The Productive C# podcast <a href="https://anchor.fm/productivecsharp/episodes/19--Global-Usings-in-C-10-e10or3e?ref=daveabrock.com" rel="nofollow">talks about global usings in C# 10</a>.</li><li>The Coding Blocks podcast <a href="https://www.codingblocks.net/podcast/making-money-with-code/?ref=daveabrock.com" rel="nofollow">talks about making money with code</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-195-orleans-with-reuben-bond/?ref=daveabrock.com" rel="nofollow">discusses Orleans with Reuben Bond</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1739&ref=daveabrock.com" rel="nofollow">discusses Visual Studio 2022</a>.</li><li>The Azure DevOps podcast <a href="http://azuredevopspodcast.clear-measure.com/customized-build-agents-with-ahmed-ilyas-episode-140?ref=daveabrock.com" rel="nofollow">talks about customizing build agents</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Azure Enablement <a href="https://channel9.msdn.com/Shows/Azure-Enablement/How-to-plan-for-cloud-adoption?ref=daveabrock.com" rel="nofollow">plans for cloud adoption</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Supporting-VBNET-in-NET-5?ref=daveabrock.com" rel="nofollow">talks about supporting VB.NET in .NET 5</a> and <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Ranges?ref=daveabrock.com" rel="nofollow">C# ranges</a>.</li><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Project-Reunion?ref=daveabrock.com" rel="nofollow">talks about Project Reunion</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #49: 🌟 Is reflection really that bad? ]]></title>
        <description><![CDATA[ Let&#39;s talk about reflection and source generators, IdentityServer template news, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/05/15/dotnet-stacks-49/</link>
        <guid isPermaLink="false">60990a3155f561003b8198f4</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 15 May 2021 05:30:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-40.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, which was released on May 10, 2021. To get the issues right away, subscribe at <a href="https://dotnetstacks.com/?ref=daveabrock.com">dotnetstacks.com</a> or at the bottom of this post.</em></p><p>Happy Monday! I hope you have a good week. Here's what we have this week:</p><ul><li>Is reflection still valuable?</li><li>IdentityServer templates shipping with .NET 6</li><li>Last week in the .NET world</li></ul><hr><h2 id="is-reflection-still-valuable">Is reflection still valuable?</h2><p>Last Monday, Marc Gravell asked: <a href="https://blog.marcgravell.com/2021/05/is-era-of-reflection-heavy-c-libraries.html?ref=daveabrock.com"><em>is the era of reflection-heavy C# libraries at an end</em></a>? As C# source generators get more popular, developers might be wondering if it might someday replace the idea of reflection (for the unfamiliar, reflection is a way of discovering types at runtime).</p><p>Today, unless we're library authors, a lot of reflection is provided to us without us having to care:</p><blockquote>This provides a pretty reasonable experience for the consumer; their code <em>just works</em>, and - sure, the library does a lot of work behind the scenes, but the library authors usually invest a decent amount of time into trying to minimize that so you aren’t paying the reflection costs every time.</blockquote><p>As the industry has evolved, we've seen how reflection impacts modern applications. For example, we see increased demands on parallel code (async/await), AOT platforms, runtime error discovery, and more. If you're thinking of the cloud, runtime performance matters (especially if you're paying for serverless and execution times).</p><p>Marc states:</p><blockquote>Imagine you could take your reflection-based analysis code, and inject it <em>way</em> earlier - in the build pipe, so when your <em>library consumer</em> is building <em>their</em> code ...  you get given the compiler’s view of the code ... and <em>at that point</em> you had the chance to <em>add your own code</em> ... and have our additional code included in the build ... This solves <em>most</em> of the problems we’ve discussed.</blockquote><p>This doesn't mean reflection doesn't have its use cases, and it's so pervasive in the .NET ecosystem it <a href="https://twitter.com/davidfowl/status/1389317488882552832?ref=daveabrock.com">isn't going anywhere anytime soon</a>. Source generators are great for resolving performance headaches with certain reflection use cases like with <code>GetTypes().</code> Should we go all-in on source generators, though? Is it worth moving code into a user's app and build processes over developers enjoying the separation? </p><p>Here's another consideration: is reflection just getting a bad rap? It can be slow for sure, but the .NET team has noted that performance is improving, and <a href="https://twitter.com/davidfowl/status/1389673507500351490?ref=daveabrock.com">there's a prototype they're working on making 10x faster</a>.</p><p>It'll be interesting to see how far the .NET platform pushes on source generators over improving reflection performance. I'm guessing we'll see a little in Column A and a little in Column B. Everything is a tradeoff. Still, it's promising to see source generators shake up decades of thinking reflection is the only way to inspect types dynamically.</p><h2 id="identityserver-templates-shipping-with-net-6">IdentityServer templates shipping with .NET 6</h2><p>Last December, IdentityServer <a href="https://blog.duendesoftware.com/posts/20201210_community_edition/?ref=daveabrock.com">introduced a licensing model</a> (and <a href="https://www.daveabrock.com/2020/10/09/dotnet-stacks-20/">we talked about it back in issue #20</a>). You'll need to buy a license if your organization makes more than 1M USD/year (I know I have a global audience but believe me, you don't want me converting currency). </p><p>This week, Barry Dorrans announced that <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-6-and-authentication-servers/?ref=daveabrock.com">.NET 6 will continue to ship these templates</a> (using the new RPL-licensed version). I personally applaud Microsoft's decision to continue to support IdentityServer, which is getting pushback from the blog's comments and <a href="https://github.com/dotnet/aspnetcore/issues/32494?ref=daveabrock.com">a super-spicy GitHub issue</a>. A lot of the pushback comes from folks accusing IdentityServer of a "bait and switch"—as if profiting off free open-source software for a decade wasn't enough—and that Microsoft should build it themselves.</p><p>As Microsoft has said a bunch of times, and <a href="https://github.com/dotnet/aspnetcore/issues/32494?ref=daveabrock.com#issuecomment-834666754">bears repeating</a>:</p><blockquote>As stated we are not authentication experts, we have no expertise in writing or maintaining an authentication server. We have a team at Microsoft dedicated to that, and they produce AAD. The .NET team will not be writing production ready authentication servers, both because of the cost in that and because in doing so it's likely we'll cannibalize users from existing open source projects, something the community was very vocal in wanting us not to do when the initial discussions around IdentityServer inclusion was started.</blockquote><hr><h2 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><p>We have a lot of great community posts this week.</p><h3 id="%F0%9F%94%A5-the-top-4">🔥 The Top 4</h3><ul><li>Marc Gravell <a href="https://blog.marcgravell.com/2021/05/is-era-of-reflection-heavy-c-libraries.html?ref=daveabrock.com">asks: is the era of reflection-heavy C# libraries at an end?</a></li><li>Thomas Ardal <a href="https://blog.elmah.io/adding-captcha-on-form-posts-with-asp-net-core/?ref=daveabrock.com">adds CAPTCHA on form posts with ASP.NET Core</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/clearable-time-picker-in-xamarin-forms/?ref=daveabrock.com">wires up a clearable time picker</a>.</li><li>Christopher Gill <a href="https://devblogs.microsoft.com/nuget/add-a-readme-to-your-nuget-package?ref=daveabrock.com">announces README NuGet package support</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/05/04/blog/posts/net-foundation-march-april-2021-update?ref=daveabrock.com">provides its March/April update</a>.</li><li>JetBrains .NET Days Online <a href="https://pages.jetbrains.com/dotnet-days-2021/dnf?ref=daveabrock.com">is happening this week</a>.</li><li>The .NET Docs Show talks to Greg Cannon <a href="https://www.youtube.com/watch?v=t-rFj54BsDI&ref=daveabrock.com">about using .NET to build an e-ink dashboard for home automation</a>.</li><li>In community standups: ASP.NET <a href="https://www.youtube.com/watch?v=enAskgcF0c0&t=4589s&ref=daveabrock.com">talks about minimal APIs</a>, Entity Framework <a href="https://www.youtube.com/watch?v=Gjys0Yebobk&ref=daveabrock.com">discusses triggers</a>, and Xamarin <a href="https://www.youtube.com/watch?v=AQHZQ8p6FCA&ref=daveabrock.com">talks single-project architecture</a>.</li></ul><h3 id="%F0%9F%95%B8-web-development">🕸 Web development</h3><ul><li>Michael Shpilt <a href="https://michaelscodingspot.com/slow-asp-net-server/?ref=daveabrock.com">writes about ASP.NET server problems and solutions</a>.</li><li>Khalid Abuhakmeh introduces Razor <a href="https://khalidabuhakmeh.com/what-is-razor-aspnet?ref=daveabrock.com">introduces Razor</a>.</li><li>Chinedu Imoh <a href="https://www.telerik.com/blogs/introduction-json-web-tokens-jwt?ref=daveabrock.com">introduces JSON Web Tokens</a>.</li><li>Kristján Oddsson <a href="https://github.blog/2021-05-04-how-we-use-web-components-at-github/?ref=daveabrock.com">writes how GitHub uses Web Components</a>.</li><li>The Code Maze blog uses <a href="https://code-maze.com/using-the-problemdetails-class-in-asp-net-core-web-api/?ref=daveabrock.com">the ProblemDetails class in ASP.NET Core Web API</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/05/03/create-an-oidc-credential-issuer-with-mattr-and-asp-net-core/?ref=daveabrock.com">creates an OIDC credential issuer with Mattr and ASP.NET Core</a>.</li><li>Jan Tattermusch <a href="https://grpc.io/blog/grpc-csharp-future/?ref=daveabrock.com">talks about grpc-dotnet</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>The Packt blog <a href="https://packt.medium.com/upgrading-existing-net-apps-to-net-5-e3768052ec44?ref=daveabrock.com">writes about upgrading existing .NET Apps to .NET 5</a>.</li><li>Maarten Balliauw <a href="https://blog.maartenballiauw.be/post/2021/05/05/building-a-supply-chain-attack-with-dotnet-nuget-dns-source-generators-and-more.html?ref=daveabrock.com">builds a supply chain attack with .NET, NuGet, DNS, source generators, and more</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>AWS announces <a href="https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-aws-sdk-for-net-version-2-v2/?ref=daveabrock.com">the end of support for AWS SDK for .NET version 2 (v2)</a>.</li><li>Lily Ma <a href="https://devblogs.microsoft.com/azure-sdk/messaging-sdks?ref=daveabrock.com">writes about Azure Event Grid, Event Hubs, and Service Bus Library Improvements</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Lost-In-Azure-Cloud-Identity-Serie-Part2/?ref=daveabrock.com">continues writing about Azure Identity</a>.</li><li>Abhijit Jana <a href="https://dailydotnettips.com/getting-started-with-azure-web-pubsub-service/?ref=daveabrock.com">gets started with the Azure Web PubSub Service</a>, then <a href="https://dailydotnettips.com/create-a-messaging-app-using-azure-web-pubsub-service-and-c/?ref=daveabrock.com">creates a messaging app using Azure Web PubSub Service and C#</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Ian Russell <a href="https://www.softwarepark.cc/blog/2021/5/1/alternate-ways-of-creating-single-case-discriminated-unions-in-f?ref=daveabrock.com">uses alternate ways of creating single-case discriminated unions in F#</a>.</li><li>Peter Vogel <a href="https://visualstudiomagazine.com/articles/2021/04/07/csharp-9.aspx?ref=daveabrock.com">writes about value objects in C# 9</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/covariance-and-contravariance-in-csharp-explained/?ref=daveabrock.com">writes about covariance and contravariance in C#</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/05/01/c-make-your-delegates-asynchronous-from-synchronous-delegates/?ref=daveabrock.com">makes C# synchronous delegates asynchronous</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/creating-a-simple-moving-average-calculator-in-csharp-1-a-simple-moving-average-calculator/?ref=daveabrock.com">creates a simple moving average calculator</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Abhijit Jana <a href="https://dailydotnettips.com/visual-studio-2022/?ref=daveabrock.com">writes about Visual Studio going 64-bit</a>.</li><li>Ali Ok <a href="https://developers.redhat.com/blog/2021/05/05/kubernetes-configuration-patterns-part-2-patterns-for-kubernetes-controllers/?ref=daveabrock.com">writes about Kubernetes configuration patterns</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/05/06/visual-studio-code-did-you-know-you-can-generate-an-installation-command-of-your-installed-extensions/?ref=daveabrock.com">generates an installation command for VS Code installed extensions</a>, and also <a href="https://anthonygiretti.com/2021/05/05/postman-i-love-you-but-i-met-thunder-client-for-visual-studio-code/?ref=daveabrock.com">writes about Thunder Client, a way for you to work with APIs right in VS Code</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-7?ref=daveabrock.com">provides his weekly MAUI update</a>.</li><li>Craig Dunn <a href="https://devblogs.microsoft.com/surface-duo/dual-screen-xamarin-forms-animation?ref=daveabrock.com">creates dual-screen apps</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Derek Comartin <a href="https://codeopinion.com/event-based-architecture-what-do-you-mean-by-event/?ref=daveabrock.com">unpacks the “event” term</a>.</li><li>Pieter Humphrey <a href="https://www.infoq.com/articles/serverless-data-api/?ref=daveabrock.com">writes about the value of serverless data APIs</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/evolving-modular-monoliths-1-an-architecture-for-net/?ref=daveabrock.com">writes about evolving modular monoliths</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>On the Software Engineering Podcast, <a href="https://www.se-radio.net/2021/05/episode-458-daniel-roth-on-blazor/?ref=daveabrock.com">Daniel Roth talks about Blazor</a>.</li><li>Serverless Chats <a href="https://www.serverlesschats.com/99/?ref=daveabrock.com">talks about multi-cloud</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-376-Azure-Media-Services?ref=daveabrock.com">talks to David Giard about Azure Media Services</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Simplify-moving-resources-between-regions-with-Azure-Resource-Mover?ref=daveabrock.com">talks about the Azure Resource Mover</a>.</li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/Building-Accessible-Mobile-Apps--The-Xamarin-Show?ref=daveabrock.com">builds accessible mobile apps</a>.</li><li>The Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox?ref=daveabrock.com">talks about EF Core</a>.</li><li>The DevOps Lab <a href="https://channel9.msdn.com/Shows/DevOps-Lab/On-Prem-To-The-Cloud-Security-is-Not-an-Afterthought-episode-9?ref=daveabrock.com">talks about cloud security</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Tuple-Pattern-Matching?ref=daveabrock.com">talks about tuple pattern matching C#</a>, <a href="https://www.youtube.com/watch?v=vYUKC0mZFqI&ref=daveabrock.com">uses Azure managed identities</a>, and <a href="https://www.youtube.com/watch?v=THVD4nzi8vk&ref=daveabrock.com">adds machine learning to .NET apps with ML.NET</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Azure Static Web Apps is production-ready: These are my 5 favorite things ]]></title>
        <description><![CDATA[ In this post, I recap my favorite things about Azure Static Web Apps. ]]></description>
        <link>https://www.daveabrock.com/2021/05/13/azure-static-web-apps-favorite-things/</link>
        <guid isPermaLink="false">6099490155f561003b81990c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 12 May 2021 20:21:12 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/azure-static-web-apps.jpg" medium="image"/>
        <content:encoded><![CDATA[ <p>As the modern web gets insanely complicated, the industry is clamoring for the simplicity of static web apps. The <a href="https://jamstack.org/?ref=daveabrock.com">Jamstack movement</a> has impacted how we design full-stack web applications. With static web apps, you can pre-render static content to a CDN—and make them dynamic through calls to APIs and serverless functions. It's fast, performant, and a dirt-cheap proposition—in many cases, you're only responsible for compute costs.</p><p>Last May, Microsoft stepped into the already busy static web app market with its <a href="https://azure.microsoft.com/en-us/services/app-service/static/?ref=daveabrock.com">Azure Static Web Apps offering</a>. (Yes, you could—and still can!—accomplish this through Azure Storage and Azure CDN, but it's a lot of manual setup and maintenance.)  </p><p>With Azure Static Web Apps, you integrate your front-end—with JavaScript frameworks like Angular, React, Svelte, and Vue or C#'s Blazor component library—with a backend powered by Azure Functions. You can even deploy with static site frameworks like Hugo, Jekyll, and Gatsby. </p><p>Why do you want everything under one umbrella? It offers the following benefits:</p><ul><li>GitHub and Azure DevOps integration, where changes in your repo trigger build and deployments</li><li>Your content is globally distributed</li><li>Azure Static Web Apps works with APIs from a reverse-proxy model, meaning you don't have to deal with CORS configuration headaches</li><li>Automated staging versions are generated whenever you open a pull request</li></ul><p>I've played with Azure Static Web Apps for the last six months with my <a href="https://www.daveabrock.com/tag/blast-off-blazor/">Blast Off with Blazor blog series</a>. Azure Static Web Apps have evolved quite a bit, and Microsoft <em>just </em>ditched the preview label (like, <em>hours ago</em>). Microsoft doesn't typically recommend public preview bits for production-scale workloads, so this is big news: it's ready, and it scales, and ships with a Standard (non-free) tier with enterprise capabilities like bringing your own Azure Functions and a 99.95% SLA.</p><p>You can read a lot of posts and docs that'll introduce you to Azure Static Web Apps. (<a href="https://www.daveabrock.com/2020/10/13/azure-functions-static-apps-blazor/">Can I suggest mine</a>?) In this post, though, I'll take a different perspective: here are 5 of my favorite things. </p><h2 id="deployment-environments">Deployment environments</h2><p>Let's say you have a trigger that is based on changes to your <code>main</code> branch. When you create a pull request against that branch, your changes are also <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests?ref=daveabrock.com">deployed to a temporary non-production environment</a>.</p><p>Here's how it looked for me:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/temp-site-1.png" class="kg-image" alt loading="lazy" width="1105" height="256" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/temp-site-1.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/temp-site-1.png 1000w, https://www.daveabrock.com/content/images/2021/05/temp-site-1.png 1105w" sizes="(min-width: 720px) 720px"></figure><p>You can push new updates to this environment as long as the PR is still open. This is useful when previewing changes, sending updates out to your team for approval and review, and so on. Once changes are merged into your branch, it disappears.</p><p><strong>NOTE!</strong> <em>Currently, staged environments are accessible by a public URL, so to quote Elmer Fudd: "Be vewy, vewy careful." </em></p><h2 id="authentication-and-authorization-support">Authentication and authorization support</h2><p>Out of the "free" box (if you don't want to open your wallet for the Standard plan), Azure Static Web Apps supports authorization with Azure AD, GitHub, and Twitter. Based on the provider, you send users invites from the Azure Portal (which assigns them to specific roles), and in a <code>staticwebapp.config.json</code> file, they are granted access to routes.</p><p>You can streamline access through <code>/.auth/login/{provider}</code>, and that URL is consistent all the way to production. In addition, you can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?ref=daveabrock.com">set up redirect rules to authorize a provider and even block other ones</a>:</p><pre><code class="language-json">{
  "route": "/login",
  "redirect": "/.auth/login/github"
}</code></pre><pre><code class="language-json">{
  "route": "/.auth/login/twitter",
  "statusCode": "404"
}</code></pre><p>With that in place, you can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript&ref=daveabrock.com">reference client authentication data</a> from a direct-access endpoint with <code>/.auth/me</code>.</p><p>If you're on the Standard paid plan, you can also set up custom authentication—with this approach, you can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=aad&ref=daveabrock.com">authenticate with any provider that supports OIDC</a>.</p><h2 id="cli-support">CLI support</h2><p>It's great to clickety-click in the Azure Portal (yes, that's the technical term), but that doesn't scale. You'll need to automate your deployments eventually. To do this, you can use the Azure CLI's <code>az staticwebapp</code> commands.</p><p>Once you have an app in your repository (either GitHub or Azure DevOps), execute <code>az login</code>, login with your credentials, then create your Azure Static Web Apps instance <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript&ref=daveabrock.com#create-a-static-web-app">with something like this</a>:</p><pre><code class="language-bash">az staticwebapp create \
    -n my-static-web-app \
    -g my-static-web-app-rg \
    -s https://github.com/daveabrock/my-static-web-app \
    -l eastus2 \
    -b main \
    --token &lt;LOL_nice_try&gt;</code></pre><p>Of course, the CLI is not a one-trick pony. If you <a href="https://docs.microsoft.com/en-us/cli/azure/staticwebapp?view=azure-cli-latest&ref=daveabrock.com">check out the docs</a>, you can also work with app settings, manage the environment, manage users, and more.</p><p>You can <em>also </em>download the official <a href="https://github.com/Azure/static-web-apps-cli?ref=daveabrock.com">Azure Static Web Apps CLI</a> from npm or Yarn. This will supercharge your local development experience. Speaking of local development...</p><h2 id="local-development-isnt-an-afterthought">Local development isn't an afterthought</h2><p>The thing about the cloud is ... well, it works great <em>in the cloud</em>. The local experience is often an afterthought. It's hard to predict how our apps work in the cloud without targeting our specific cloud resources. You can use the Azure Static Web Apps CLI to do a lot of heavy lifting for you. </p><p>The CLI provides a static site server, a proxy to your API endpoints, a mock authentication and authorization server, and more. This chart, <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/local-development?ref=daveabrock.com">borrowed from the docs</a>, illustrates it better than I ever could (so I'll just <s>steal</s> borrow it):</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/image-16.png" class="kg-image" alt loading="lazy" width="1000" height="654" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/image-16.png 600w, https://www.daveabrock.com/content/images/2021/05/image-16.png 1000w" sizes="(min-width: 720px) 720px"></figure><p>You can run <code>swa start</code> to start your app, and even call some other API with the <code>--api</code> flag—this API doesn't even need to be part of your Azure Static Web Apps resource! So, that's nice. But really, I want to focus on the star of this show: the authorization and authentication emulator, which simulates the Azure security flow. </p><p>When a user logs in locally, you define a mocked identity profile. Earlier, we talked about GitHub authorization. In this case, when browsing to <code>/.auth/login/github</code>, you'll <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/local-development?ref=daveabrock.com#authorization-and-authentication-emulation">see a page that lets you define a profile</a>. </p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/image-19.png" class="kg-image" alt loading="lazy" width="1656" height="1198" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/image-19.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/image-19.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/image-19.png 1600w, https://www.daveabrock.com/content/images/2021/05/image-19.png 1656w" sizes="(min-width: 720px) 720px"></figure><p>You can define client principal values here, use <code>/.auth/me</code> to get a client principal, and then execute the <code>/.auth/logout</code> endpoint to clear the principal and log out the mock user. I have absolutely no interest in mocking Azure authentication myself. This is a wonderful feature.</p><h2 id="apex-domain-support">Apex domain support </h2><p>This is a little tongue-in-cheek, but I can't help but get excited about root/APEX domain support—this gives you the ability to configure your site at <em>blastoffwithblazor.com</em> and not just <em>www.blastoffwithblazor.com</em>. Previously, you had to hack your way around Cloudflare using <a href="https://burkeholland.github.io/posts/static-app-root-domain/?ref=daveabrock.com">Burke Holland's blog post</a> to do this, but no more! (Sorry, Burke—no, your Google Analytics is not playing games on you.) </p><p>This support was missing throughout the previews because of the impacts, but you can now do this <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain?tabs=azure-dns&ref=daveabrock.com#add-domain-using-txt-record-validation">through simple TXT record validation</a>. After you enter your domain in the Azure Portal, configure a TXT record with your provider to prove ownership, then create an ALIAS record back in the Azure Portal. </p><h2 id="wrap-up">Wrap up</h2><p>In this post, I recapped my favorite things about Azure Static Web Apps: deployment environments, CLI support, the local development environment, authentication and authorization support, and apex domain support.</p><p>How has your experience been? Let me know in the comments!</p><p>  </p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Migrating my site from Jekyll to Ghost ]]></title>
        <description><![CDATA[ I&#39;ve migrated my site from Jekyll to Ghost. ]]></description>
        <link>https://www.daveabrock.com/2021/05/10/migrating-my-site-jekyll-ghost/</link>
        <guid isPermaLink="false">60994c0955f561003b819914</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 10 May 2021 11:17:47 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1519337265831-281ec6cc8514?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJsb2dnaW5nfGVufDB8fHx8MTYyMDY2MDAyMg&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>You may have noticed things are looking a little different around here. I've completely redesigned my website and even moved to a new platform, Ghost Pro (hosted). I was previously using Jekyll over GitHub Pages. It took a little bit of work, but I found a great theme (yes, I know, I'm famous for switching themes all the time), found out <a href="https://ghost.org/integrations/custom-rss/?ref=daveabrock.com">how not to break existing RSS feeds</a>, and learned <a href="https://ghost.org/docs/themes/routing/?ref=daveabrock.com">how not to break my links</a>. I'm happy with how it turned out.</p><p>Jekyll was great. So why did I switch?</p><p>Over the last 18 months, I've gone from being a typical "I should blog more" developer to pushing out content consistently twice a week. It's been quite the experience: like working with code over time, some pieces I'm proud of, some make me cringe, but I'm happy with my progress. </p><p>I love serving the community, but it can be time-consuming (like most community members, most of my work is on my own time on top of a busy family life and a day job). I easily spend a few hours a month (if not more) on maintaining various aspects of my Jekyll site. As I'm trying to serve the developer community in different ways, I've lost the passion for maintaining my site myself. These days, I want to open a browser and write. (I did try various Jekyll CMS's, but none were a good fit.) I want to be as productive as I can and am OK with not having complete control over every part of my site. It's your textbook IaaS vs. PaaS vs SaaS argument: do you want convenience or control? </p><p>That's not to say the time spent maintaining my site was wasted. I enjoyed learning about static site generators and the Ruby ecosystem. It's just not something I want to invest time in anymore. I'm also very happy with Ghost as a CMS. From a pure writing and publishing perspective, I think it's a better and more productive experience <em>for me</em>.</p><p>After taking a fresh look at my site, it was a good opportunity to find a decent commenting system.</p><h2 id="scrapping-disqus">Scrapping Disqus</h2><p>Some time ago, I scrapped comments altogether on my site. Comments are a great way to engage (and learn, improve, and exchange ideas with my readers) but I couldn't handle Disqus, the most popular (and free) commenting system. It's bloated, has <a href="https://supunkavinda.blog/disqus?ref=daveabrock.com">a sketchy tracking history</a>, and a suspect advertising engine. In terms of performance, I shouldn't have to read articles on <a href="https://css-tricks.com/lazy-loading-disqus-comments/?ref=daveabrock.com">lazy-loading Disqus comments</a> just to make its performance acceptable. So, I scrapped Disqus until I could find a better alternative.</p><p>I've decided to use Commento, a commenting system <a href="https://www.commento.io/?ref=daveabrock.com">that is focused on privacy and performance</a>. I see a lot of folks I trust are using it, and I like what I see so far. It does come with a cost, but it's minimal (and is covered my generous GitHub sponsors, <a href="https://swimburger.net/?ref=daveabrock.com">Niels Swimberghe</a> and <a href="https://twitter.com/ThomasArdal?ref=daveabrock.com">Thomas Ardal</a>). I'm more than happy to support good software.</p><p>I hope you enjoy the new site. If you don't (or you do), please let me know in the comments. Thanks for reading!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #48: ⚡ Sockets. Sockets everywhere. ]]></title>
        <description><![CDATA[ What is Azure Web PubSub, and how is it different than SignalR? ]]></description>
        <link>https://www.daveabrock.com/2021/05/08/dotnet-stacks-48/</link>
        <guid isPermaLink="false">60986f085396f6003e95819d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 08 May 2021 18:26:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-39.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, which was released on May 08, 2021. To get the issues right away, subscribe at <a href="https://dotnetstacks.com/?ref=daveabrock.com">dotnetstacks.com</a> or at the bottom of this post.</em></p><p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li><strong><strong>One big thing</strong></strong>: Microsoft announces Azure Web PubSub</li><li><strong><strong>The little thing</strong></strong>: Logging middleware coming, new try-convert release, and EF perf improvements</li><li>Last week in the .NET world</li></ul><hr><h2 id="microsoft-announces-azure-web-pubsub">Microsoft announces Azure Web PubSub</h2><p>Last week, Microsoft rolled out a <a href="https://azure.microsoft.com/blog/easily-build-realtime-apps-with-websockets-and-azure-web-pubsub-now-in-preview?ref=daveabrock.com">public preview of Azure Web PubSub</a>, a managed service for building real-time web applications using web sockets. According to Microsoft, Azure Web PubSub enables you to use WebSockets and the publish-subscribe pattern to build real-time web applications easily. This service helps you manage a lot of concurrent WebSocket connections for data-intensive apps. In these scenarios, implementing at scale is a challenge. It lowers the barrier to entry: all you need is a WebSocket client and an HTTP client. Think about simple messaging patterns with a lot of connections. What’s nice here is that you can use any addressable endpoint with Azure Web PubSub. Azure Web PubSub integrates with Azure Functions natively, with the capability to build serverless apps with WebSockets and C#, Python, Java, or JavaScript. You use anything that can connect from a web socket, even desktop apps.</p><p>Here’s what’s on our minds: how is this different than the SignalR service? While both services are internally built from similar tech, the most significant difference is that there’s no client or protocol requirement with Azure Web PubSub. You can bring your WebSocket library if you wish. And also, unlike SignalR, you’re just working with WebSockets here—you won’t see automatic reconnect scenarios, long polling, and whatnot.</p><p>What does this mean for SignalR? Nothing. As a matter of fact, according to David Fowler, here’s when you’d want to stick with SignalR:</p><ul><li>You’re a .NET-specialized dev shop and have SignalR client libraries and expertise</li><li>You need fallbacks other than WebSockets, like long polling or server-sent events</li><li>The existing SignalR client platforms work for you</li><li>You don’t want to manage a custom protocol and need more complex patterns (and want SignalR to manage it for you)</li><li>You don’t want to manage the reconnect logic yourself</li></ul><p>Anthony Chu sums it up pretty well <a href="https://twitter.com/nthonyChu/status/1388010951144722432?ref=daveabrock.com">when he says</a>:</p><blockquote>Personally, I would use SignalR unless you need to support clients that don’t have a supported SignalR library. You could write the code connect/reconnect/messaging code yourself but SignalR does it all for you with a nice API.</blockquote><p>Speaking of WebSockets, WebSocket compression <a href="https://github.com/dotnet/runtime/pull/49304?ref=daveabrock.com">is coming to .NET 6</a> thanks to a community contribution from Ivan Zlatanov. It’s an opt-in feature, and it looks like <a href="https://twitter.com/ivan_zlatanov/status/1387528689479569409?ref=daveabrock.com">Blazor won’t be using it for now</a>. Security problems can arise when server messages contain payloads from users and, as a result, shouldn’t be compressed.</p><hr><h2 id="the-little-things-logging-middleware-coming-new-try-convert-release-and-ef-perf-improvements">The little things: Logging middleware coming, new try-convert release, and EF perf improvements</h2><p>As we discussed last week, .NET 6 Preview 4 will be a big release with lightweight APIs and AOT on the list (if not more). For Preview 5, ASP.NET Core will be <a href="https://github.com/dotnet/aspnetcore/issues/31843?ref=daveabrock.com">introducing logging middleware</a>. Logging request and response information isn’t the most fun, so middleware will do a lot of the heavy lifting for you (and you can extend it if needed). By default, the logging middleware won’t log response bodies, but <a href="https://twitter.com/JustinKotalik/status/1388249145916358656?ref=daveabrock.com">that should be a configuration detail</a>. This is a problem every ASP.NET developer has to deal with, so it’s nice to see it being generalized.</p><hr><p>A new try-convert <a href="https://github.com/dotnet/try-convert/releases/tag/v0.7.222801?ref=daveabrock.com">release was shipped last week</a>. This release includes enhancements for VB.NET Windows Forms conversions. The new, snazzy .NET Upgrade Assistant relies on this try-convert tool, which means VB.NET WinForms support has arrived with the Upgrade Assistant. That’s all I’m going to say about that because the more you talk about VB.NET, the more someone calls you an expert.</p><hr><p>I missed this last week, but the Entity Framework team announced the results from new TechEmpower benchmarks. It looks like EF Core 6 is 33% faster than EF Core 5, and EF Core is also almost 94% of the Dapper performance.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/EntityFramework?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#EntityFramework</a> biweekly update <a href="https://twitter.com/hashtag/efcore?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#efcore</a><br><br>TechEmpower Fortunes perf!<br><br>⏫ EF Core 6.0 is 33.1% faster than EF Core 5.0<br>⏫ Dapper is also 6.0% faster<br>⏫ EF Core is now at 93.5% of Dapper perf<br><br>Plus: learn to contribute! We live-streamed a PR end-to-end.<a href="https://t.co/8kfj4du1wC?ref=daveabrock.com">https://t.co/8kfj4du1wC</a> <a href="https://t.co/qGRT2GT2e3?ref=daveabrock.com">pic.twitter.com/qGRT2GT2e3</a></p>&mdash; Arthur Vickers (@ajcvickers) <a href="https://twitter.com/ajcvickers/status/1385335542334705665?ref_src=twsrc%5Etfw&ref=daveabrock.com">April 22, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h3 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h3><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Brian Lagunas <a href="https://brianlagunas.com/c-yield-return-what-is-it-and-how-does-it-work/?ref=daveabrock.com">walks through yield return in C#</a>.</li><li>Giorgi Dalakishvili <a href="https://www.giorgi.dev/dotnet/introducing-graphqlinq-strongly-typed-graphql-queries-with-linq-to-graphql/?ref=daveabrock.com">introduces GraphQLinq, a LINQ-to-GraphQL library</a>.</li><li>Microsoft announces <a href="https://azure.microsoft.com/blog/easily-build-realtime-apps-with-websockets-and-azure-web-pubsub-now-in-preview?ref=daveabrock.com">Azure Web PubSub</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Microsoft announces that <a href="https://devblogs.microsoft.com/dotnet/net-framework-4-5-2-4-6-4-6-1-will-reach-end-of-support-on-april-26-2022?ref=daveabrock.com">.NET Framework 4.5.2, 4.6, 4.6.1 will reach End of Support on April 26, 2022</a>.</li><li>Asia Rudenko <a href="https://blog.jetbrains.com/dotnet/2021/04/23/resharper_rider_2021_1_2/?ref=daveabrock.com">introduces ReSharper 2021.1.2 and Rider 2021.1.2</a>.</li><li>Uno writes about <a href="https://platform.uno/blog/uno-platform-3-7-more-winui-project-reunion-and-linux-support-wasm-performance-boost/?ref=daveabrock.com">Uno Platform 3.7</a>.</li><li>Alexandra Kolesova writes how <a href="https://blog.jetbrains.com/dotnet/2021/04/26/resharper-and-rider-2021-2-will-require-net-framework-4-7-2-on-windows/?ref=daveabrock.com">ReSharper and Rider 2021.2 will require .NET Framework 4.7.2 or newer installed on Windows</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>The Azure SDK <a href="https://devblogs.microsoft.com/azure-sdk/planning-2021?ref=daveabrock.com">wants your feedback on the next phase of the Azure SDK</a>.</li><li>Alberto Gimeno <a href="https://github.blog/2021-04-27-ship-code-faster-safer-feature-flags/?ref=daveabrock.com">writes how GitHub uses feature flags</a>.</li><li>Microsoft Build registration <a href="https://register.build.microsoft.com/?ref=daveabrock.com">is now open</a>.</li><li>Maarten Balliauw <a href="https://blog.jetbrains.com/dotnet/2021/04/28/resharper-and-visual-studio-2022-64-bit/?ref=daveabrock.com">comments on ReSharper and Visual Studio 2022 64-bit</a>.</li><li>For community standups: ASP.NET <a href="https://www.youtube.com/watch?v=Nb5lV2i8bCI&ref=daveabrock.com">talks about SPA updates</a> and Machine Learning talks about <a href="https://www.youtube.com/watch?v=KlZje8GNDEQ&ref=daveabrock.com">.NET Notebooks and .NET Interactive</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=4fw2c_ukABM&ref=daveabrock.com">talks to Irina Scurtu about versioning APIs</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Jeremy Likness <a href="https://blog.jeremylikness.com/blog/multitenancy-with-ef-core-in-blazor-server-apps/?ref=daveabrock.com">works on multi-tenancy with EF Core in Blazor Server apps</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/04/26/securing-an-asp-net-core-app-and-web-api-using-windows-authentication/?ref=daveabrock.com">secures an ASP.NET Core app and Web API using Windows auth</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/04/29/introduction-to-blazor-form-handling-and-input-validation/?ref=daveabrock.com">works on Blazor form handling and input validation </a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/blazor-material-form-creation-with-file-upload-and-dialogs/?ref=daveabrock.com">works on Blazor material form creation with file uploads and dialogs</a>.</li><li>Daniel Jiminez Garcia <a href="https://www.dotnetcurry.com/aspnet-core/realtime-app-using-blazor-webassembly-signalr-csharp9?ref=daveabrock.com">uses Blazor WebAssembly, SignalR and C# 9 to create Full-stack Real-time Applications</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/blazor/2021/04/24/Blazor-IntersectionObserver-WebApi.html?ref=daveabrock.com">works with the IntersectionObserver API in Blazor</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/access-background-services-from-aspnet-core?ref=daveabrock.com">accesses background services from ASP.NET Core</a>.</li><li>Waqas Anwar <a href="https://www.ezzylearning.net/tutorial/how-to-support-multiple-versions-of-asp-net-core-web-api?ref=daveabrock.com">supports multiple versions of ASP.NET Core Web API</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/we-dont-need-winui-for-uwp/?ref=daveabrock.com">explains why he doesn’t want or need WinUI for UWP</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/net-6-has-a-linux-shaped-hole-23010395d11e?ref=daveabrock.com">writes about a lack of Linux support for .NET 6 desktop apps</a>.</li><li>Sam Walpole <a href="https://dev.to/dr_sam_walpole/linq-beware-of-deferred-execution-59db?ref=daveabrock.com">warns against deferred execution in LINQ</a>.</li><li>Maarten Balliauw <a href="https://blog.jetbrains.com/dotnet/2021/04/27/sherlock-holmes-and-the-case-of-a-crashing-devenv-exe/?ref=daveabrock.com">investigates a crashing devenv.exe</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Matias Quaranta <a href="https://devblogs.microsoft.com/cosmosdb/improve-net-sdk-initialization?ref=daveabrock.com">writes about improving your Azure Cosmos DB .NET SDK initialization</a>.</li><li>Carlos Souza <a href="https://www.pluralsight.com/blog/it-ops/aws-vs-azure-containers?ref=daveabrock.com">compares deploying containers in Azure and AWS</a>.</li><li>Jessica Deen <a href="https://devblogs.microsoft.com/devops/rearchitecting-for-microservices-featuring-windows-linux-containers?ref=daveabrock.com">refactors for microservices using Linux and Windows containers</a>.</li><li>Jamie Maguire <a href="https://jamiemaguire.net/index.php/2021/04/24/aspect-based-sentiment-analysis-with-azure-cognitive-services-text-analytics-preview/?ref=daveabrock.com">works on aspect-based sentiment analysis with Azure Cognitive Services Text Analytics</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Damir Arh <a href="https://www.dotnetcurry.com/csharp/nullable-reference-types-csharp?ref=daveabrock.com">discusses nullable reference type best practices</a>.</li><li>Jonathan Allen <a href="https://www.infoq.com/news/2021/04/Net6-Linq/?ref=daveabrock.com">walks through .NET 6 LINQ improvements</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/read-write-excel-spreadsheets-with-csharp?ref=daveabrock.com">reads and writes Excel spreadsheets in C#</a>.</li><li>Tom Deseyn <a href="https://developers.redhat.com/blog/2021/04/27/some-more-c-9/?ref=daveabrock.com">completes his series on C# 9 features</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Billy Griffin <a href="https://github.blog/2021-04-28-github-desktop-hiding-whitespace-expanding-diffs-repo-aliases/?ref=daveabrock.com">writes about GitHub Desktop updates</a>.</li><li>Davide Bellone <a href="https://www.code4it.dev/blog/fluentvalidation?ref=daveabrock.com">works with FluentValidation</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/04/29/meet-dapr?ref=daveabrock.com">makes microservices fun again with Dapr</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/trying-out-the-open-source-ecommerce-platform-nopcommerce-using-docker/?ref=daveabrock.com">tries out the open-source eCommerce platform nopCommerce using Docker</a>.</li><li>Rory Primrose <a href="https://www.neovolve.com/2021/04/25/nsubstitute-and-fluentassertions-redux/?ref=daveabrock.com">revisits NSubstitute and FluentAssertions</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/api-testing?ref=daveabrock.com">writes about strategy and tools for APIs</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Leomaris Reyes <a href="https://askxammy.com/replicating-book-worm-ui-in-xamarin-forms/?ref=daveabrock.com">replicates a Book Worm UI in Xamarin Forms</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-6?ref=daveabrock.com">provides his weekly MAUI update</a>.</li><li>Matt Lacey <a href="https://www.infoq.com/articles/uno-xamarin/?ref=daveabrock.com">writes about Uno Platform and Xamarin.Forms</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Derek Comartin <a href="https://codeopinion.com/aggregate-design-using-invariants-as-a-guide/?ref=daveabrock.com">talks about aggregate design</a>.</li><li>The NDepend blog <a href="https://blog.ndepend.com/clean-architecture-refactoring-a-case-study/?ref=daveabrock.com">writes about a Clean Architecture refactoring case study</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-75-dependency-injection-with-steve-collins/?ref=daveabrock.com">talks about dependency injection with Steve Collins</a>.</li><li>The Productive C# Podcast <a href="https://anchor.fm/productivecsharp/episodes/18--DateOnly-and-TimeOnly-structs-in--NET-6-evl2dp?ref=daveabrock.com">discusses the new DateOnly and TimeOnly structs in C#</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/a-special-group-presentation-on-blazor-architecture-episode-138?ref=daveabrock.com">discusses Blazor architecture</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-374-Keeping-up-with-Azure?ref=daveabrock.com">talks about keeping up with Azure</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-066-interactive-c-with-vs-code-notebooks-with-eric-potter/?ref=daveabrock.com">talks about interactive C# with VS Code Notebooks</a>.</li><li>The .NET Rocks show <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1737&ref=daveabrock.com">talks with Simon Cropp about Verify</a>.</li><li>The Coding Blocks podcast <a href="https://www.codingblocks.net/podcast/write-great-apis/?ref=daveabrock.com">talks about writing great APIs</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Authentication-for-Serverless-apps-with-Easy-Auth?ref=daveabrock.com">talks about authentication for serverless apps</a>, <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Init-only-setters?ref=daveabrock.com">init-only setters</a>, <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Default-Interface-Methods?ref=daveabrock.com">default interface methods in C#</a>, and <a href="https://www.youtube.com/watch?v=eIlbBAQ6fUk&ref=daveabrock.com">GitHub Codespaces</a>.</li><li>Azure Enablement <a href="https://channel9.msdn.com/Shows/Azure-Enablement/Evaluating-financial-considerations-during-your-cloud-adoptionjourney?ref=daveabrock.com">talks about cloud financial considerations</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #47: 🧨 Now with 32 more bits ]]></title>
        <description><![CDATA[ This week, we talk about Visual Studio 2022, API updates, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/05/01/dotnet-stacks-47/</link>
        <guid isPermaLink="false">60986c7e5396f6003e95813b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 01 May 2021 18:13:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-38.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>NOTE: This is the web version of my weekly newsletter, which was released on April 26, 2021. To get the issues right away, subscribe at <a href="https://dotnetstacks.com/?ref=daveabrock.com">dotnetstacks.com</a> or at the bottom of this post.</em></p><p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li><strong><strong>One big thing</strong></strong>: Visual Studio 2022 to be 64-bit</li><li><strong><strong>The little thing</strong></strong>: API updates coming to Preview 4, memory dump tooling, dotnet monitor updates</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-visual-studio-2022-to-be-64-bit">One big thing: Visual Studio 2022 to be 64-bit</h2><p>Last week, I <a href="https://daveabrock.com/2021/04/24/dotnet-stacks-46?ref=daveabrock.com">provided a tooling update</a>. Figuring the next major updates would occur around Build, it was a good time to get up to speed. I pushed the newsletter, started my workday, then an hour later, Amanda Silver wrote a post about <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com">Visual Studio 2022</a>. Oops.</p><p>The biggest news: Visual Studio 2022 will be 64-bit and is no longer chained to limited memory (4 gigs or so) in the main <em>devenv.exe</em> process. If you look at <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com#visual-studio-2022-is-64-bit">Silver’s post</a>, she has a video of a 64-bit Visual Studio app working easily with 1600 projects and 300k files. Finally.</p><p>With <a href="https://web.archive.org/web/20170922120502/https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/2255687-make-vs-scalable-by-switching-to-64-bit?page=1&per_page=20">interest dating back in 2011</a>, the Visual Studio team responded in 2016, saying that “at this time we don’t believe the returns merit the investment and resultant complexity.” Times have changed—hardware capabilities have improved, and VS is no longer the only .NET IDE option—and it’s now worth it.</p><p>For example, if you look at the issue <a href="https://developercommunity.visualstudio.com/t/Visual-Studio-x64-implementation/1372671?space=8&ftype=idea&sort=votes&stateGroup=active&ref=daveabrock.com">in the Developer Community</a>, a few comments echo what Microsoft has heard for a few years now:</p><blockquote>This year my company(size 15k+) started to provide RAIDER to employees and plans to cancel our Enterprise VS subscriptions as VS is highly unproductive because of memory limitations of 32 bit application.</blockquote><blockquote>Lately I’m mainly using Rider. It does about 80% of what VS does, but it does that 80% without worrying about running out of ram.</blockquote><p>To be clear, as <a href="https://visualstudiomagazine.com/articles/2021/04/19/vs-2022.aspx?ref=daveabrock.com">David Ramel notes</a>, Visual Studio has been available in a 64-bit edition to create 64-bit apps on 64-bit machines, but the application itself has previously been a 32-bit app. JetBrains <a href="https://twitter.com/JetBrainsRider/status/1384164326328606728?ref=daveabrock.com">cheekily welcomed Visual Studio to the 64-bit club</a>, but this also means ReSharper will have more room to breathe. When the time comes, you’ll need to grab 64-bit versions of your favorite extensions as well.</p><p>Of course, 64-bit support isn’t the only thing coming to Visual Studio 2022. VS 2022 promises a <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com#designing-for-everyone">better UI interface</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com#diagnostics-and-debugging">enhanced diagnostics and debugging</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com#insights-and-productivity">productivity updates</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/?ref=daveabrock.com#improved-code-search">improved code search</a>, and more. The first preview will ship this summer, with UI refinements and accessibility improvements. In the meantime, you can <a href="https://developercommunity.visualstudio.com/search?space=8&ftype=idea&sort=votes&stateGroup=active&ref=daveabrock.com">check out the most requested features from the community</a>.</p><hr><h2 id="the-little-things-api-updates-coming-to-preview-4-async-analyzers-dotnet-monitor-updates">The little things: API updates coming to Preview 4, async analyzers, dotnet monitor updates</h2><p><br>A couple weeks ago, we talked <a href="https://daveabrock.com/2021/04/10/dotnet-stacks-44?ref=daveabrock.com">about the FeatherHttp project</a>, a lightweight, scalable way of writing APIs without the typical overhead that comes with .NET APIs today.</p><p>Here’s what I said about it:</p><blockquote>Fowler says the repo has three key goals: to be built on the same primitives on .NET Core, to be optimized to build HTTP APIs quickly, and having the ability to take advantage of existing .NET Core middleware and frameworks. According to a GitHub comment, the solution uses 90% of ASP.NET Core and changes the Startup pattern to be more lightweight.</blockquote><p>That functionality will start rolling out in .NET 6 Preview 4 in a few weeks. (Along with AOT support, Preview 4 promises to be a satisfying update.)</p><p>David Fowler tweeted about it and the discussion was spicy.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Want to throw together a quick web application in C#? This is what that will look like in the future. <a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://twitter.com/hashtag/aspnetcore?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#aspnetcore</a> <a href="https://t.co/3RR8uYdS1o?ref=daveabrock.com">pic.twitter.com/3RR8uYdS1o</a></p>&mdash; David Fowler 🇧🇧💉 (@davidfowl) <a href="https://twitter.com/davidfowl/status/1385290460613144577?ref_src=twsrc%5Etfw&ref=daveabrock.com">April 22, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>I’m personally excited to give this a spin. If it isn’t your jam, it doesn’t have to be—it isn’t a breaking change, and you can always use your current solution. But as APIs evolve with microservices, much of the core logic is done outside of the endpoints anyway, so you may find you don’t need the complexity and overhead with writing APIs in MVC.</p><hr><p>Mark Downie and his team have been doing some great work with managed memory dump analyzers. If you think that’s too low-level, reconsider—when logging and local debugging fail you (or issues aren’t reproducible easily), memory dump analysis can be your friend. It isn’t always easy to work with memory dumps, though. To help folks new to dump debugging, Microsoft has developed a new <a href="https://docs.microsoft.com/visualstudio/debugger/how-to-debug-managed-memory-dump?view=vs-2019&ref=daveabrock.com">.NET Diagnostics Analyzer tool</a> to quickly identify or rule out issues.</p><p>A great use case is <a href="https://devblogs.microsoft.com/visualstudio/managed-memory-dump-analyzers/?ref=daveabrock.com">finding async anti-patterns</a>, a common cause of thread starvation, which only may become prevelant when you hit high production workloads. Check out the blog post to see how it can detect some “sync-over-async” issues.</p><hr><p>In passing, we’ve talked about the dotnet monitor tool. It allows you to access diagnostics information with a dotnet process. It’s no longer experimental: it’s <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-dotnet-monitor/?ref=daveabrock.com">now a supported tool in the .NET ecosystem</a>. Sourabh Shirhatti wrote about <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-dotnet-monitor/?ref=daveabrock.com">that and recent updates</a>.</p><hr><p>Lastly, a nice tip from Khalid Abuhakmeh:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">In <a href="https://twitter.com/dotnet?ref_src=twsrc%5Etfw&ref=daveabrock.com">@dotnet</a> 6 preview 3+ you can validate IOptions on application startup. No misconfiguration issues in production. <a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://twitter.com/hashtag/aspnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#aspnet</a> <a href="https://twitter.com/hashtag/aspnetcore?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#aspnetcore</a> <a href="https://t.co/Rg7w4OhVWL?ref=daveabrock.com">pic.twitter.com/Rg7w4OhVWL</a></p>&mdash; Khalid 🪀 (@buhakmeh) <a href="https://twitter.com/buhakmeh/status/1385329674276966407?ref_src=twsrc%5Etfw&ref=daveabrock.com">April 22, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h3 id="%F0%9F%8C%8E-last-week-in-the-net-world">🌎 Last week in the .NET world</h3><h3 id="%F0%9F%94%A5-the-top-3">🔥 The Top 3</h3><ul><li>Kristoffer Strube <a href="https://blog.elmah.io/rendering-dynamic-content-in-blazor-wasm-using-dynamiccomponent/?ref=daveabrock.com">works with DynamicComponent in Blazor</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/are-you-starting-xamarin-forms-lets-create-simple-ui?ref=daveabrock.com">writes about getting started with Xamarin Forms</a>.</li><li>Konrad Kokosa <a href="https://tooslowexception.com/net-quiz-check-your-level-of-knowledge-about-net-memory-management/?ref=daveabrock.com">has a quiz to check your level of knowledge about .NET memory management</a>.</li></ul><h3 id="%F0%9F%93%A2-announcements">📢 Announcements</h3><ul><li>Amanda Silver <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022?ref=daveabrock.com">rolls out Visual Studio 2022</a>.</li><li>Sourabh Shirhatti <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-dotnet-monitor?ref=daveabrock.com">writes about what’s new in dotnet monitor</a>.</li><li>Mark Downie <a href="https://devblogs.microsoft.com/visualstudio/managed-memory-dump-analyzers?ref=daveabrock.com">announces memory dump analyzers that detect async antipatterns</a>.</li></ul><h3 id="%F0%9F%93%85-community-and-events">📅 Community and events</h3><ul><li>GitHub rolls out <a href="https://github.blog/2021-04-19-open-source-goes-to-mars/?ref=daveabrock.com">a new Mars 2020 Helicopter Mission badge</a>.</li><li>Maarten Balliauw <a href="https://blog.jetbrains.com/dotnet/2021/04/19/new-net-guide-tutorials-from-visual-studio-to-rider-resharper-essentials-docker-and-more/?ref=daveabrock.com">announces new .NET tutorials from JetBrains</a>.</li><li>Microsoft is putting on <a href="https://dev.to/dotnet/let-s-learn-net-c-free-live-stream-event-1ak0?ref=daveabrock.com">a free live stream event on Friday called “Let’s Learn .NET”</a>.</li><li>Shahed Chowdhuri <a href="https://wakeupandcode.com/azure-simplified-new-video-series/?ref=daveabrock.com">is launching a new “Azure, Simplified” video series</a>.</li><li>For weekly standups: ASP.NET <a href="https://www.youtube.com/watch?v=Mot8qAWEnj8&ref=daveabrock.com">talks about .NET 6 ASP.NET Core updates</a> and Entity Framework <a href="https://www.youtube.com/watch?v=9OMxy1wal1s&ref=daveabrock.com">shows off how to contribute</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=9OMxy1wal1s&ref=daveabrock.com">optimizes Linux containers with Robert Rozas</a>.</li></ul><h3 id="%F0%9F%8C%8E-web-development">🌎 Web development</h3><ul><li>Matthew Jones <a href="https://exceptionnotfound.net/tetris-in-blazor-part-5-controls-upcoming-tetrominos-and-clearing-rows/?ref=daveabrock.com">continues building a Tetris app in Blazor</a>.</li><li>Jeff Fritz <a href="https://jeffreyfritz.com/2021/04/introducing-kliptok/?ref=daveabrock.com">introduces his KlipTok project</a>.</li><li>Jon Hilton asks: <a href="https://jonhilton.net/blazor-prerendering-net6/?ref=daveabrock.com">will .NET 6 fix Blazor Prerendering</a>?</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/04/23/building-a-dashboard-blazor/?ref=daveabrock.com">builds a dashboard in Blazor</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/asp-net-core-web-api/why-asp-net-core-frombody-not-working-returning-null?ref=daveabrock.com">explains why the ASP.NET Core FromBody can return null</a>.</li><li>Sardar Mudassar Ali <a href="https://www.c-sharpcorner.com/article/how-to-test-asp-net-core-web-api-service-with-swagger/?ref=daveabrock.com">tests an ASP.NET Core 5 Web API service with Swagger</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/04/19/store-data-of-your-blazor-app-in-the-local-storage-and-in-the-session-storage/?ref=daveabrock.com">works with local storage and session storage in Blazor</a>.</li><li>Muhammad Rehan Saeed <a href="https://rehansaeed.com/css-general-rules-of-thumb/?ref=daveabrock.com">writes about CSS best practices</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/04/19/securing-multiple-auth0-apis-in-asp-net-core-using-oauth-bearer-tokens/?ref=daveabrock.com">secures multiple Auth0 APIs in ASP.NET Core using OAuth bearer tokens</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-mudblazor-to-create-product-details-page/?ref=daveabrock.com">uses MudBlazor to work with a product detail page</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/add-svelte-to-aspnet-core-projects?ref=daveabrock.com">adds Svelte to ASP.NET Core projects</a>.</li></ul><h3 id="%F0%9F%A5%85-the-net-platform">🥅 The .NET platform</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/fixing-build-warning-netsdk1138-when-building-end-of-life-projects-with-dotnet-5/?ref=daveabrock.com">fixes a build warning when building projects with end-of-life .NET frameworks</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/04/21/top-vs-requests.aspx?ref=daveabrock.com">writes about the top feature requests for Visual Studio 2022</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/converting-a-13-year-old-net-wpf-app-called-babysmash-to-a-selfcontained-net-5-app-with-the-net-upgrade-assistant?ref=daveabrock.com">converts his 13-year-old .NET BabySmash app to a self-contained .NET 5 app with the .NET Upgrade Assistant</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/conversation-about-crossgen2?ref=daveabrock.com">talks about the crossgen2 tool</a>.</li></ul><h3 id="%E2%9B%85-the-cloud">⛅ The cloud</h3><ul><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Lost-In-Azure-Cloud-Identity-Series-Introduction/?ref=daveabrock.com">starts a series on Azure Identity</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/623/building-and-auto-deploying-an-aspnet-core-application-part-6-setting-up-a-cd-pipeline-deploying-to-an-azure-app-service?ref=daveabrock.com">deploys to the Azure App Service</a>.</li><li>The AWS Blog <a href="https://aws.amazon.com/blogs/developer/dive-into-the-aws-sdk-for-dotnet-runtime-pipeline/?ref=daveabrock.com">writes about the AWS SDK for .NET’s runtime pipeline and client configuration</a>, and also <a href="https://aws.amazon.com/blogs/developer/introducing-aws-toolkit-for-visual-studio-support-for-aws-sso-and-assume-role-with-mfa/?ref=daveabrock.com">introduces the AWS Toolkit for Visual Studio support for AWS SSO and Assume Role with MFA</a>.</li><li>GitHub Actions <a href="https://github.blog/2021-04-22-github-actions-update-helping-maintainers-combat-bad-actors/?ref=daveabrock.com">rolls out protections to fight cryptomining</a>.</li></ul><h3 id="%F0%9F%93%94-languages">📔 Languages</h3><ul><li>Brian Lagunas <a href="https://brianlagunas.com/task-vs-valuetask-when-should-i-use-valuetask/?ref=daveabrock.com">compares Task and ValueTask</a>.</li><li>Tom Deseyn <a href="https://developers.redhat.com/blog/2021/04/20/c-9-init-accessors-and-records/?ref=daveabrock.com">works with init accessors and records in C# 9</a>.</li></ul><h3 id="%F0%9F%94%A7-tools">🔧 Tools</h3><ul><li>Steve Smith <a href="https://ardalis.com/add-imgbot-to-github-repository/?ref=daveabrock.com">adds ImgBot to his GitHub repository</a>.</li><li>Paul DeVito <a href="https://wrapt.dev/blog/integration-tests-using-sql-server-db-in-docker?ref=daveabrock.com">works on .NET Core integration tests using a SQL Server database in Docker</a>.</li><li>Jay Krishna Reddy <a href="https://www.c-sharpcorner.com/article/cqrs-mediatr-in-net-5/?ref=daveabrock.com">uses CQRS with MediatR in .NET 5</a>.</li><li>ErikEJ <a href="https://erikej.github.io/efcore/azure/2021/04/20/efcore-managed-identity.html?ref=daveabrock.com">uses Entity Framework Core with Azure Managed Identity, App Service/Functions, and Azure SQL DB</a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/orchard-core-net5-and-csharp9?ref=daveabrock.com">works with Orchard Core, .NET 5, and C# 9</a>.</li><li>Auth0 <a href="https://auth0.com/blog/introducing-auth0-cli/?ref=daveabrock.com">introduces a new CLI</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/fix-dotnet-icu-build-issues-in-github-actions?ref=daveabrock.com">fixes .NET ICU build issues in GitHub Actions</a>.</li></ul><h3 id="%F0%9F%93%B1-xamarin">📱 Xamarin</h3><ul><li>Rakeshkumar Desai <a href="https://www.c-sharpcorner.com/article/getting-started-with-net-maui-first-impressions/?ref=daveabrock.com">gets started with .NET MAUI</a>.</li><li>Almir Vuk <a href="https://www.infoq.com/articles/net-maui/?ref=daveabrock.com">talks to David Ortinau about .NET MAUI</a>.</li></ul><h3 id="%F0%9F%8F%97-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Derek Comartin asks: <a href="https://codeopinion.com/do-microservices-require-containers-docker-kubernetes/?ref=daveabrock.com">do microservices require containers, Docker, or Kubernetes</a>?</li><li>Scott Hannen <a href="https://scotthannen.org/blog/2021/04/19/partial-optional-object-population.html?ref=daveabrock.com">writes about the Partial/Optional Object Population (POOP) anti-pattern</a>. (Finally, a blog post suitable for both me and my 3-year-old.)</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/easily-create-and-manipulate-mock-anonymous-data-for-unit-tests?ref=daveabrock.com">creates and manipulates mock anonymous data for unit tests</a>.</li></ul><h3 id="%F0%9F%8E%A4-podcasts">🎤 Podcasts</h3><ul><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-74-libvlcsharp-and-net-with-martin-finkel/?ref=daveabrock.com">talks about libvlcsharp and .NET with Martin Finkel</a>.</li><li>The Complete Developer podcast <a href="https://completedeveloperpodcast.com/quickly-learning-new-technology/?ref=daveabrock.com">talks about quickly learning new technologies</a>.</li><li>The Productive C# Podcast <a href="https://anchor.fm/productivecsharp/episodes/17--How-to-become-a-fluent-C-developer-with-Codingame-ev5pf6?ref=daveabrock.com">discusses how to become a fluent C# developer with Codingame</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-192-blazor-with-carl-franklin/?ref=daveabrock.com">talks about Blazor with Carl Franklin</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1736&ref=daveabrock.com">talks to Gerald Versluis about going from Xamarin to MAUI</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/250?ref=daveabrock.com">answers your questions</a>.</li><li>Serverless Chats <a href="https://www.serverlesschats.com/97/?ref=daveabrock.com">discusses how serverless fits in to the cyclical nature of the industry</a>.</li></ul><h3 id="%F0%9F%8E%A5-videos">🎥 Videos</h3><ul><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Getting-Started-with-Jupyter-Notebooks-in-VS-Code?ref=daveabrock.com">gets started with Jupyter notebooks in VS Code</a>.</li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Build-Automation-with-NUKE?ref=daveabrock.com">talks about build automation with NUKE</a>, <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Top-level-statements?ref=daveabrock.com">works through top-level statements in C# 9</a>, and <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Using-Static-Directive?ref=daveabrock.com">uses the static directive in C#</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Make microservices fun again with Dapr ]]></title>
        <description><![CDATA[ Let&#39;s take a look at Dapr, a distributed application runtime that promises to make working with microservices easier. ]]></description>
        <link>https://www.daveabrock.com/2021/04/29/meet-dapr/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fea2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 28 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1548092372-0d1bd40894a3?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIxfHxjb21wdXRlcnxlbnwwfHx8fDE2MTk4MDQ0NjM&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>If you can manage a monolithic application correctly, often it’s all you need: building, testing, and deploying is relatively straightforward. If you manage this well—embracing the concepts of <a href="https://codeopinion.com/loosely-coupled-monolith?ref=daveabrock.com">a loosely-coupled monolith</a>—you can get away from a lot of the complexity of modern distributed applications.</p><p>In theory, though, I’ve seen monoliths open for abuse. After some time, the monolith becomes complicated, changes are filled with unintended side effects, and it becomes difficult to manage. Even simple changes require full deployments of the entire application, and testing is a nightmare. In these cases, you may want to consider a microservice architecture. With anything else, you need to understand what you’re getting yourself into.</p><p>Instead, you’re signing up to manage a bunch of smaller applications with a lot to consider: how can I monitor and observe my services? How can I make them robust and resilient? How can I work with async communication, like messaging and event-driven patterns? When I do need to be synchronous, how can I handle that? How can I scale? Did I mention it has to be cloud-native through containerization and a container orchestrator like Kubernetes?</p><p>Three months after your stakeholders ask you to build a shopping cart, you’re looking at an app filled with complex dependencies, cobbled-together SDKs, and complicated configuration setups. You now spend your days futzing with YAML files—and believe me, some days it’s a word dangerously close to <em>futzing</em>—and you can’t help but wonder: wasn’t I supposed to be developing things?</p><p>Dapr, or Distributed Application Runtime, is here to help. Production-ready <a href="https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/?ref=daveabrock.com">since February</a> and sponsored by Microsoft, it manages distributed applications for you through a “building blocks” mechanism. These pluggable components manage the various layers of complexity for you:</p><ul><li>State management</li><li>Invoking services</li><li>Bindings</li><li>Observability</li><li>Secrets</li><li>Actors</li></ul><p>In these cases, you tell Dapr which “component to use”—like Redis or SQL Server, for instance—and Dapr will handle the rest for you through a singular SDK or API. While you may be worried about a single layer of abstraction, this provides a lot of value over other options like Istio or Orleans: one SDK to manage all your complexity.</p><p>Dapr uses a sidecar pattern. From your services, you can connect to Dapr from HTTP or gRPC. Here’s what it looks like (this graphic was <a href="https://docs.dapr.io/concepts/overview/?ref=daveabrock.com#self-hosted">stolen from the Dapr Docs</a>):</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/overview-sidecar.png" class="kg-image" alt loading="lazy" width="781" height="304" srcset="https://www.daveabrock.com/content/images/size/w600/2021/04/overview-sidecar.png 600w, https://www.daveabrock.com/content/images/2021/04/overview-sidecar.png 781w" sizes="(min-width: 720px) 720px"></figure><p>Even more, you can enjoy the benefits from your local machine. You can configure Dapr to run the <a href="https://github.com/dapr/cli?ref=daveabrock.com#launch-dapr-and-your-app">Dapr CLI</a>.</p><p>You may think you need to Dapr-ize your entire application if you want to leverage it—this is not true. If you feel you could benefit by doing pub-sub over HTTP, use that piece and leave the rest of the application alone. This isn’t an all-or-nothing approach.</p><p>Before we proceed with one of my favorite Dapr use cases, let’s answer a common question.</p><h2 id="is-this-a-new-service-mesh">Is this a new Service Mesh?</h2><p>Is this a new Service Mesh? Thankfully, no.</p><p>If you’re unfamiliar, a service mesh is an infrastructure layer that can provide capabilities like load-balancing, telemetry, and service-to-service communication. In many ways, you might think abstracting these capabilities away from the services themselves is a step forward. In reality, though, I hate them so much. Adding another hop in your service to a complicated mesh that requires a talented I&amp;O team to administer, coupled with a terrible developer experience? No, thanks. When I see these solutions, I wonder: does anyone think about the people who build applications?</p><p>While these meshes use a sidecar pattern like Dapr, it is <em>not</em> a dedicated network infrastructure layer but a distributed application runtime. While a service mesh enables things from the network perspective, Dapr has that and more: application-level capabilities like actors that can encapsulate logic and data, complex state management, bindings, and more.</p><p>This isn’t a binary decision, of course—you <em>could</em> <a href="https://docs.dapr.io/concepts/faq/?ref=daveabrock.com#networking-and-service-meshes">add service meshes with Dapr</a> to isolate networking concerns away from application concerns.</p><h2 id="get-your-feet-wet-with-simplified-pub-sub">Get your feet wet with simplified pub-sub</h2><p>Because Azure Service Bus does not provide a great local development experience—and <a href="https://github.com/Azure/azure-service-bus/issues/223?ref=daveabrock.com">not without some discussion on making it better</a>—it isn’t uncommon to see developers use RabbitMQ locally and in development environments but Azure Service Bus in production. As <a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/reference-application?ref=daveabrock.com#benefits-of-applying-dapr-to-eshop">with the <em>Dapr for .NET Developers</em> ebook</a>, you can provide an abstraction layer, but swapping between the two is a lot of work.</p><p>Here’s an example, using the Dapr .NET SDK, for publishing an event to a <code>concert</code> topic:</p><pre><code class="language-csharp">var band = new Band
{
  Id = 1,
  Name = "The Eagles, man"
};

var daprClient = new DaprClientBuilder().Build();

await daprClient.PublishEventAsync&lt;OrderData&gt;("pubsub", "concert", band);</code></pre><p>The Dapr SDK allows you to decorate your <code>ActionResult</code> methods with a <code>Topic</code> attribute. For example, here’s how a <code>CreateBand</code> signature would look:</p><pre><code class="language-csharp">[Topic("pubsub", "concert")]
[HttpPost("/bands")]
public async Task&lt;ActionResult&gt; CreateBand(BandModel band)</code></pre><p>In ASP.NET Core, you’ll need to let the middleware know you’re working with Dapr in the <code>ConfigureServices</code> and <code>Configure</code> methods:</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    // other stuff omitted
    services.AddControllers().AddDapr();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // other stuff omitted
    app.UseCloudEvents();

    app.UseEndpoints(endpoints =&gt;
    {
        endpoints.MapSubscribeHandler();
    });
}
</code></pre><p>If I was using <a href="https://v1-rc1.docs.dapr.io/operations/components/setup-pubsub/supported-pubsub/setup-rabbitmq/?ref=daveabrock.com">RabbitMQ with Dapr</a>, I would include something like this in my configuration:</p><pre><code class="language-yaml">apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub-rq
spec:
  type: pubsub.rabbitmq
  version: v1
  metadata:
  - name: host
    value: "amqp://localhost:5672"
  - name: durable
    value: true
  - name: deletedwhenunused
    value: true
</code></pre><p>If I wanted to swap it out with Azure Service Bus, I could update my configuration. (Each provider has various configuration levels, <a href="https://v1-rc1.docs.dapr.io/operations/components/setup-pubsub/supported-pubsub/setup-azure-servicebus/?ref=daveabrock.com">as you can see</a>.)</p><pre><code class="language-yaml">apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: &lt;NAME&gt;
  namespace: &lt;NAMESPACE&gt;
spec:
  type: pubsub.azure.servicebus
  version: v1
  metadata:
  - name: connectionString
    value: &lt;myconnectionstring&gt; 
  - name: timeoutInSec
    value: 75 
  - name: maxDeliveryCount
    value: 3
  - name: lockDurationInSec
    value: 30
</code></pre><p>With the Dapr pub/sub model, a nice benefit is the capability to subscribe to a topic in a declarative fashion. In this example, I can define the Dapr component, the topic to subscribe to, the API to call, and which services have pub/sub capabilities.</p><pre><code class="language-yaml">apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
  name: concert-subscription
spec:
  pubsubname: pubsub
  topic: concert
  route: /bands
scopes:
- ThisService
- ThatService
- TheOtherService
</code></pre><p>While a quick example—I plan a future dedicated post of Dapr pub-sub—you can see the benefits, especially when swapping dependencies. In the <em>Dapr for .NET Developers</em> ebook, Microsoft says they could <a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/reference-application?ref=daveabrock.com#benefits-of-applying-dapr-to-eshop">remove 700 lines of code</a> using Dapr to switch between RabbitMQ and Azure Service Bus.</p><h2 id="conclusion">Conclusion</h2><p>In this article, we introduced Dapr. We walked through the problems it solves, how it compares to a Service Mesh, and a simple scenario using pub-sub with RabbitMQ and Azure Service Bus. As I’m just beginning to get my feet wet, look for more posts on the topic soon!</p><h2 id="references">References</h2><ul><li><a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/?ref=daveabrock.com">Dapr for .NET Developers</a> (a good read and inspiration for the use case I provided, check it out)</li><li><a href="https://docs.dapr.io/concepts/overview/?ref=daveabrock.com">Dapr Docs</a></li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #46: 📒 What&#x27;s new with your favorite IDE ]]></title>
        <description><![CDATA[ This week, we talk about IDE updates, the .NET Upgrade Assistant, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/04/24/dotnet-stacks-46/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fea1</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 23 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/04/THE-.NET-STACKS.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li><strong>One big thing</strong>: Catching up on your IDEs</li><li><strong>The little thing</strong>: More on the Upgrade Assistant, k8s in Microsoft Learn, bUnit news</li><li>Last week in the .NET world</li></ul><hr><h1 id="one-big-thing-catching-up-on-your-ides">One big thing: Catching up on your IDEs</h1><p>There’s been a lot of news lately on the IDE front. Whether you’re using Visual Studio or JetBrains Rider, there have been some big releases that are worth reviewing. (I’m focusing on IDEs here—I realize you can do .NET in VS Code, but that’s more of an editor, even if it can sometimes feel like an IDE with the right extensions.)</p><p>As for VS, last Wednesday, Microsoft <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com">released Visual Studio 2019 v16.10 Preview 2</a>. From the .NET perspective (C++ is not part of the .NET family, so I don’t mention those), it includes many IntelliSense updates. You’ll now see <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#completions-for-casts-indexers-and-operators">completions for casts, indexers, and operators</a>, the ability to <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#automatically-insert-method-call-arguments">automatically insert method call arguments when writing method calls</a>, a <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#user-interface-for-editorconfig-files">UI for working with EditorConfig files</a>, and a <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#user-interface-for-editorconfig-files">new way to visualize inheritance</a>.</p><p>The release also contains <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#new-features-for-containers">new features for working with containers</a>: you can <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#run-launch-services-defined-in-your-compose-files">run services defined from your Docker Compose files</a>, and there’s also a <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#advanced-interactions-with-containers-and-images">new containers tooling window</a>. You’ll also see some nice improvements with the Test Explorer. You can finally <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#view-console-logs-in-the-test-explorer">view console logs there</a>, <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#navigate-links-from-log-files">navigate to links from log files</a>, and <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?ref=daveabrock.com#automatically-create-log-files">automatically create log files</a>.</p><p>Finally, Visual Studio has pushed out updates to the Git experience. With v16.10, Visual Studio’s status bar now features an enhanced branch picker, a repository picker, and a sync button. You can also select a commit to open an embedded view of its details and the file changes in the Git Repository window without having to navigate to other windows (an excellent way to compare commits). You can learn about the Git changes <a href="https://devblogs.microsoft.com/visualstudio/enhanced-productivity-with-git-in-visual-studio/?ref=daveabrock.com">in a devoted blog post</a>. With the admission I haven’t checked it out in a while, I’ve found the Git experience not to be very feature-rich. I might have to check it out again.</p><p>What about Rider? Earlier this month, <a href="https://blog.jetbrains.com/dotnet/2021/04/08/rider-2021-1-release/?ref=daveabrock.com">JetBrains wrote about the Rider 2021.1 release</a>. If you work in ASP.NET MVC, Web APIs, or Razor Pages, Rider now features scaffolding for Areas, Controllers, Razor Pages, Views, and Identity. It also generates boilerplate code for EF CRUD operations. Rider now supports ASP.NET Core route templates with inspections to check HTTP syntax errors and quick-fixes to fix route parameter issues.</p><p>They’ve also made some improvements to support the latest C# features: there’s increased support for patterns and records, and Rider has a new set of inspections and quick-fixes with records themselves. If you’re into tuples, Rider now allows you to use them with its refactoring tooling. They’ve even started looking at C# 10 and have taught Rider to work with the new “Constant interpolation strings” feature.</p><p>You can check out the <a href="https://www.jetbrains.com/rider/whatsnew/?ref=daveabrock.com"><em>What’s New in Rider</em> page</a> for all the details on their latest release.</p><hr><h1 id="the-little-things-more-on-the-upgrade-assistant-k8s-in-microsoft-learn-bunit-news">The little things: More on the Upgrade Assistant, k8s in Microsoft Learn, bUnit news</h1><p>Last week, I talked about hot reload in .NET 6. A few of you were kind enough to let me know that you were having issues seeing the GIFs. If you were having problems, I apologize (you can look at the <a href="https://daveabrock.com/2021/04/17/dotnet-stacks-45?ref=daveabrock.com">web version of the newsletter</a> and see them in action). I was looking into hot reload for a piece for the Telerik developer blog <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">that was published last week</a>. Check it out to see how you can enable it, how it works, how it handles errors and its limitations.</p><hr><p>While I’m already doing some shameless plugs, I also <a href="https://www.telerik.com/blogs/meet-dotnet-upgrade-assistant-your-dotnet-5-moving-company?ref=daveabrock.com">wrote a piece about the .NET Upgrade Assistant</a>. We’ve mentioned it in passing, but it’s a global command-line tool that guides you through migrating your .NET Framework apps to .NET 5. It doesn’t do everything for you, as many APIs like <code>System.Web</code> isn’t available in .NET Core—but it goes a long way in doing the painful bits. It comes with an (optional) accessibility model, which allows you to customize upgrade steps without modifying the tool itself. For example, you can explicitly map NuGet packages to their replacements, add custom template files and add custom upgrade steps. To do this, you include an <code>ExtensionManifest.json</code> file.</p><p>When I migrated an MVC app, I thought about using it to delete the <code>App_Start</code> folder and its contents automatically. It isn’t supported (but <a href="https://github.com/dotnet/upgrade-assistant/issues/374?ref=daveabrock.com">is now tracked!</a>) as right now, you can only find files. In cases like these, though, I would hope this would be done automatically. But if you’re migrating a bunch of projects and know how you want to port over some code, you can customize it yourself. It should save you quite a bit of time.</p><hr><p>Kubernetes has <a href="https://docs.microsoft.com/learn/modules/aks-app-package-management-using-helm/?WT.mc_id=twitter-0000-jeffsand&ref=daveabrock.com">now made its way to Microsoft Learn</a>. Microsoft shipped a new module that walks you through application and package management using Helm. You can provision Kubernetes resources from the in-browser Azure Cloud Shell.</p><p>Did you think I’d write about Kubernetes and not leave you with a funny joke?</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">A devops engineer walks into a bar, puts the bartender in a docker container, put kubernetes behind the bar, spins up 1000 bartenders, orders 1 beer.</p>&mdash; Ben Burton (@bjburton) <a href="https://twitter.com/bjburton/status/1106908952535728128?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 16, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><p>Congrats to Egil Hansen. bUnit, his popular Blazor testing library, is <a href="https://twitter.com/egilhansen/status/1381222883976998914?ref=daveabrock.com">out of preview and has officially hit v1.0</a>. You can check out the release notes <a href="https://github.com/egil/bUnit/discussions/364?ref=daveabrock.com">for the latest release</a>.</p><hr><p>The API proposal for C# 10 interpolated strings is now officially approved. <a href="https://github.com/dotnet/runtime/issues/50601?ref=daveabrock.com">Check it out on GitHub</a>.</p><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><p></p><h2 id="-the-top-4">🔥 The Top 4</h2><ul><li>Andrew Lock <a href="https://andrewlock.net/viewing-overriden-configuration-values-in-aspnetcore/?ref=daveabrock.com">views overwritten configuration values in ASP.NET Core</a>.</li><li>Jeremy Likness <a href="https://blog.jeremylikness.com/blog/an-easier-blazor-debounce/?ref=daveabrock.com">writes about an easier way to debounce in Blazor</a>.</li><li>Steve Smith <a href="https://ardalis.com/testing-exceptions-with-xunit-and-actions/?ref=daveabrock.com">tests exceptions with XUnit and Actions</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/04/17/asp-net-core-5-entityframework-core-clean-clear-and-fluent-integration-tests-with-calzolari-testserver-entityframework-fluentassertion-web-and-xunit/?ref=daveabrock.com">uses fluent integration tests with EF Core and xUnit</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Microsoft releases <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-8-release?ref=daveabrock.com">Windows Terminal Preview 1.8</a> and <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">Visual Studio 2019 v16.10 Preview 2</a>.</li><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/april-release-2021?ref=daveabrock.com">provides its April update</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Kevin Dockx <a href="https://www.kevindockx.com/new-release-marvin-jsonpatch-2-2/?ref=daveabrock.com">updates his Marvin.JsonPatch library</a>.</li><li>The Azure Cosmos DB Conf <a href="https://gotcosmos.com/conf?ref=daveabrock.com">starts on Tuesday</a>.</li><li>JetBrains is <a href="https://blog.jetbrains.com/dotnet/2021/04/14/dotnet-days-online-2021/?ref=daveabrock.com">hosting .NET Days on May 11-12</a>.</li><li>In community standups: ASP.NET standup <a href="https://www.youtube.com/watch?v=livNmRqDnMI&ref=daveabrock.com">talks to Shaun Walker about Oqtane</a>, .NET Tooling <a href="https://www.youtube.com/watch?v=3hQB_ElxJXU&ref=daveabrock.com">talks about .NET Interactive</a>, and Machine Learning <a href="https://www.youtube.com/watch?v=o-WQyQc-rJ0&ref=daveabrock.com">holds office hours</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=A93Fn_qMLX4&ref=daveabrock.com">talks to Rehan Saeed about NuGet packages</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Ben Foster <a href="https://benfoster.io/blog/customize-authorization-response-aspnet-core/?ref=daveabrock.com">customizes authorization responses in .NET 5.0</a>.</li><li>Dave Brock <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">writes about hot reload in .NET 6</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/tetris-in-blazor-part-4-displaying-the-grid-and-a-falling-tetromino/?ref=daveabrock.com">continues writing a Tetris game in Blazor</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/generate-links-to-aspnet-core-map-endpoints?ref=daveabrock.com">generates links to ASP.NET Core map endpoints</a>, and also <a href="https://khalidabuhakmeh.com/how-to-add-models-to-aspnet-core?ref=daveabrock.com">adds models to ASP.NET Core</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/04/09/blazorwebview.aspx?ref=daveabrock.com">writes about the new Blazor WebView controls</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/blazor-material-table-paging-searching-sorting/?ref=daveabrock.com">works with tables in MudBlazor</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/04/12/securing-blazor-web-assembly-using-cookies-and-auth0/?ref=daveabrock.com">secures Blazor Web Assembly using cookies and Auth0</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/winui-uno-behaviors/?ref=daveabrock.com">adds behaviors to a WinUI Uno Application</a>.</li><li>Jonathan Allen <a href="https://www.infoq.com/news/2021/04/Net6-Async/?ref=daveabrock.com">writes about .NET 6 async improvements</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/04/12/maui-desktop.aspx?ref=daveabrock.com">writes about what’s new in .NET 6 Preview 3</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/restyling-winui-controls/?ref=daveabrock.com">restyles controls in an Uno (Windows UI) application</a>.</li><li>Laurent Ellerbach <a href="https://devblogs.microsoft.com/dotnet/show-dotnet-build-your-own-unit-test-platform-the-true-story-of-net-nanoframework?ref=daveabrock.com">writes about the story of .NET nanoFramework</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Jeff Fritz <a href="https://dev.to/dotnet/my-favorite-c-features-part-3-nullability-2mcg?ref=daveabrock.com">writes about C# nullability</a>.</li><li>Damir Arh <a href="https://www.dotnetcurry.com/csharp/simpler-code-with-csharp-9?ref=daveabrock.com">makes code simpler with C# 9</a>.</li><li>Tom Deseyn <a href="https://developers.redhat.com/blog/2021/04/13/c-9-new-features-for-methods-and-functions/?ref=daveabrock.com">writes about C# 9 new features for methods and functions</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Dave Brock <a href="https://www.telerik.com/blogs/meet-dotnet-upgrade-assistant-your-dotnet-5-moving-company?ref=daveabrock.com">writes about the .NET Upgrade Assistant</a>.</li><li>Mark Downie <a href="https://www.poppastring.com/blog/debug-managed-linux-core-dumps-with-visual-studio?ref=daveabrock.com">debugs managed Linux core dumps with Visual Studio</a>.</li><li>Munib Butt <a href="https://www.c-sharpcorner.com/article/an-introduction-to-using-ndepend-in-visual-studio/?ref=daveabrock.com">uses NDepend in Visual Studio</a>.</li><li>Craig Morten <a href="https://medium.com/asos-techblog/an-aks-performance-journey-part-1-sizing-everything-up-ee6d2346ea99?ref=daveabrock.com">starts a series on his AKS performance journey</a>.</li><li>Chandra Kudumula <a href="https://www.red-gate.com/simple-talk/cloud/data-science/insurance-price-prediction-using-machine-learning-ml-net/?ref=daveabrock.com">uses ML.NET to predict insurance rates</a>.</li><li>Pratik Nadagouda <a href="https://devblogs.microsoft.com/visualstudio/enhanced-productivity-with-git-in-visual-studio?ref=daveabrock.com">writes about using Visual Studio with Git</a>.</li><li>Gerard Gallant <a href="https://platform.uno/blog/deploying-c-web-applications-with-docker/?ref=daveabrock.com">deploys C# web applications in Docker</a>.</li><li>Aaron Stannard <a href="https://petabridge.com/blog/akkadotnet-ihostedservice/?ref=daveabrock.com">builds headless Akka.NET services with IHostedService</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/04/12/improvements-for-resharper-rider-avalonia/?ref=daveabrock.com">writes about ReSharper &amp; Rider improvements For Avalonia</a>.</li><li>Elie Bou Issa <a href="https://www.red-gate.com/simple-talk/sysadmin/devops/automating-azure-devops-logic-apps/?ref=daveabrock.com">automates Azure DevOps with Logic Apps</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-4?ref=daveabrock.com">provides another MAUI update</a>.</li><li>Selva Ganapathy Kathiresan <a href="https://www.syncfusion.com/blogs/post/replicating-a-facebook-like-ui-in-xamarin.aspx?ref=daveabrock.com">replicates a Facebook-like UI</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Grant Fritchey <a href="https://www.red-gate.com/blog/how-does-microservices-architecture-change-database-deployment?ref=daveabrock.com">explains how microservices architecture changes database deployment</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/organizing-commands-events-handlers-in-microservices/?ref=daveabrock.com">organizes microservices</a>.</li><li>Over at Software Alchemy, <a href="https://blog.jacobsdata.com/2021/04/11/scaffold-your-clean-ddd-web-application-part-6-domain-driven-design-workflow-patterns?ref=daveabrock.com">scaffolding your clean DDD web app</a>.</li><li>Scott Hannen <a href="https://scotthannen.org/blog/2021/04/12/integration-test-experiment-2.html?ref=daveabrock.com">continues writing about his experiment with making integration tests easier to write</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-064-to-ci-cd-or-not-to-ci-cd/?ref=daveabrock.com">discusses the merits of CI/CD</a>.</li><li>The Coding After Work podcast <a href="http://codingafterwork.com/2021/04/14/episode-58-blazor-podcasting-and-music-with-carl-franklin/?ref=daveabrock.com">catches up with Carl Franklin</a>.</li><li>The Working Code podcast <a href="https://www.bennadel.com/blog/4027-working-code-podcast-episode-018-feature-flags.htm?ref=daveabrock.com">discusses feature flags</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1735&ref=daveabrock.com">talks to Ian Cooper about TDD in 2021</a>.</li><li>The Changelog <a href="https://www.changelog.com/podcast/436?ref=daveabrock.com">talks to Daniel Stenberg about managing curl.</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/paul-yuknewicz-on-azure-development-episode-136?ref=daveabrock.com">talks about Azure development</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>The On .NET Show <a href="https://www.youtube.com/watch?v=P25SIYLsH-g&ref=daveabrock.com">secures apps with Microsoft Identity</a>, and <a href="https://channel9.msdn.com/Shows/On-NET/C-Language-Highlights-Target-Typed-new-expressions?ref=daveabrock.com">target-typed new expressions in C# 9</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=emp1PVEt1X8&ref=daveabrock.com">deal with truncation with string and binary values</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Meet the .NET Upgrade Assistant, Your .NET 5 Moving Company ]]></title>
        <description><![CDATA[ The .NET Upgrade Assistant is a global command-line tool that guides you through migrating your .NET Framework apps to .NET 5, automating several painful steps along the way. In this post, we review the tool by migrating an ASP.NET MVC app. ]]></description>
        <link>https://www.daveabrock.com/2021/04/18/meet-dotnet-upgrade-assistant-your-dotnet-5-moving-company/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fea0</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 17 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1601654717399-7486d5ebedca?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDR8fG1vdmluZ3xlbnwwfHx8fDE2MTk4Mjc4NzM&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em><strong>NOTE</strong>: This post originally appeared on the <a href="https://www.telerik.com/blogs/meet-dotnet-upgrade-assistant-your-dotnet-5-moving-company?ref=daveabrock.com">Progress Telerik Blog</a>.</em></p><p>Moving is just the worst.</p><p>You have to rent a truck, hope it’ll hold all your things, beg friends and family to help, and feel the pain for days after the move. And during the move, you tell yourself: “Someday, I’ll hire someone to take all this stress off my hands. Imagine what I could be doing instead of all this tedious work!” The next time you move, you hire a moving company, and it’s <em>incredible</em>. The movers handle all the heavy lifting while you focus on breaking in your new home.</p><p>This is the promise of the <a href="https://docs.microsoft.com/dotnet/core/porting/upgrade-assistant-overview?ref=daveabrock.com">.NET Upgrade Assistant</a>, a global command-line tool that helps you migrate your .NET Framework apps to .NET 5. If .NET Framework is the sturdy home that’s showing its age and getting harder to repair and .NET 5 is a modern, efficient home built with state-of-the-art materials, the .NET Upgrade Assistant is the moving company that makes your life easier.</p><p>Let’s be clear: <strong>the .NET Upgrade Assistant is not a magic wand</strong>. You’ll likely need to do some manual work as you migrate. However, the tool can do most of your heavy lifting and allow you to focus on what’s important.</p><p>What exactly does the .NET Upgrade Assistant do? In prerelease, it’s a guided tool that leads you through your migration.</p><p>It performs the following tasks:</p><ul><li>Adds analyzers that assist with upgrading</li><li>Determines which projects to upgrade and in what order</li><li>Updates your project file to the SDK format</li><li>Re-targets your projects to .NET 5</li><li>Updates NuGet package dependencies to versions compatible with .NET 5, and removes transitive dependencies present in <code>packages.config</code></li><li>Makes C# updates to replace .NET Framework patterns with their .NET 5 equivalents</li><li>Where appropriate, adds common template files</li></ul><p>The .NET Upgrade Assistant allows you to migrate from the following .NET Framework application types.</p><ul><li>Windows Forms</li><li>WPF</li><li>ASP.NET MVC apps</li><li>Console apps</li><li>Class libraries</li></ul><p>We’re going to evaluate the .NET Upgrade Assistant by migrating a legacy ASP.NET MVC app, <em>eShopLegacyMVCSolution</em>, which runs .NET Framework 4.7.2. I’ve borrowed this from <a href="https://github.com/dotnet-architecture/eShopModernizing?ref=daveabrock.com">the repository</a> for the Microsoft e-book, <em><a href="https://docs.microsoft.com/dotnet/architecture/modernize-with-azure-containers/?ref=daveabrock.com">Modernize existing .NET applications with Azure cloud and Windows containers</a></em>, by Cesar de la Torre. My <a href="https://github.com/daveabrock/UpgradeAssistantDemo?ref=daveabrock.com">daveabrock/UpgradeAssistantDemo</a> repository contains both the legacy solution and my upgraded solution. As a bonus, you can review my commit history to see how the code changes after each step.</p><h2 id="before-you-start">Before You Start</h2><p>Before you start using the Upgrade Assistant, make sure you’re familiar with Microsoft’s <a href="https://docs.microsoft.com/dotnet/core/porting/?ref=daveabrock.com">porting documentation</a> and understand the migration limitations, especially when <a href="https://docs.microsoft.com/aspnet/core/migration/proper-to-2x/?view=aspnetcore-5.0&ref=daveabrock.com">deciding to migrate ASP.NET applications</a>. Additionally, you can use the <a href="https://github.com/microsoft/dotnet-apiport?ref=daveabrock.com">.NET Portability Analyzer tool</a> to understand which dependencies support .NET 5. It’s like calling the moving company first to find out what they can and cannot move and how long it might take.</p><p>Before you install the .NET Upgrade Assistant, you must ensure you install the following:</p><ul><li><a href="https://visualstudio.microsoft.com/downloads/?ref=daveabrock.com">Visual Studio 2019 16.8 or later</a> (Visual Studio is required because the tool uses MSBuild to work with project files)</li><li>The <a href="https://dotnet.microsoft.com/download/dotnet/5.0?ref=daveabrock.com">.NET 5 SDK</a></li></ul><p>The tool also depends on the <code>try-convert</code> tool to convert project files to the SDK style. You must have version <code>0.7.212201</code> or later to use the Upgrade Assistant.</p><p>From a terminal, run the following to install the .NET Upgrade Assistant. (It’s a global tool, so you can run the command anywhere.)</p><pre><code>dotnet tool install -g try-convert
</code></pre><p>If you have <code>try-convert</code> installed but need to upgrade to a newer version, execute the following:</p><pre><code>dotnet tool update -g try-convert
</code></pre><h2 id="install-the-net-upgrade-assistant">Install the .NET Upgrade Assistant</h2><p>We’re now ready to install the .NET Upgrade Assistant. To do so, execute the following from a terminal:</p><pre><code>dotnet tool install -g upgrade-assistant
</code></pre><p>After installing the .NET Upgrade Assistant, run it by navigating to the folder where your solution exists and entering the following command.</p><pre><code>upgrade-assistant &lt;MySolution.sln&gt;
</code></pre><h2 id="use-the-upgrade-assistant-to-migrate-to-net-5">Use the Upgrade Assistant to Migrate to .NET 5</h2><p>To get started, I’ll run the following command from my terminal. (The default command should work, but if needed, you can <a href="https://github.com/dotnet/upgrade-assistant?ref=daveabrock.com#usage">pass other flags</a> like <code>--verbose</code>.)</p><pre><code>upgrade-assistant eShopDotNet5MVC.sln
</code></pre><p>The tool executes and shows me the steps it will perform. For each step in the process, I can apply the next step in the process, skip it, see details, or configure logging. Most of the time, you’ll want to select <code>Apply next step</code>. To save some time, you can press <code>Enter</code> to do this.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/0-Upgrade-Assistant-Initialize.jpg" class="kg-image" alt="The .NET Upgrade Assistant starts" loading="lazy" width="2000" height="1452" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/0-Upgrade-Assistant-Initialize.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/0-Upgrade-Assistant-Initialize.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/0-Upgrade-Assistant-Initialize.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/0-Upgrade-Assistant-Initialize.jpg 2062w" sizes="(min-width: 720px) 720px"></figure><p>When the tool starts, it places a <code>log.txt</code> file at the root of your project.</p><h3 id="back-up-project">Back Up Project</h3><p>The first step is to back up the project. The .NET Upgrade Assistant asks if you want to use a custom path for your backup or a default location. Once this completes, we’re ready to convert the project file.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/1-Back-Up-Project.jpg" class="kg-image" alt="The .NET Upgrade Assistant backs up your project" loading="lazy" width="2000" height="1236" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/1-Back-Up-Project.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/1-Back-Up-Project.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/1-Back-Up-Project.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/1-Back-Up-Project.jpg 2047w" sizes="(min-width: 720px) 720px"></figure><h3 id="convert-project-files-to-sdk-style">Convert Project Files to SDK Style</h3><p>.NET 5 projects use the SDK-style format. In this step, the Upgrade Assistant converts your project file to this SDK format using the <code>try-convert</code> tool. During this process, we see the tool is warning us that a few imports, like <code>System.Web</code>, might need manual intervention after migration.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/2-Convert-Project-File.jpg" class="kg-image" alt="The .NET Upgrade Assistant converts the project file to the SDK style" loading="lazy" width="2000" height="1509" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/2-Convert-Project-File.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/2-Convert-Project-File.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/2-Convert-Project-File.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/2-Convert-Project-File.jpg 2127w" sizes="(min-width: 720px) 720px"></figure><h3 id="update-tfm">Update TFM</h3><p>Next, the .NET Upgrade Assistant will update the Target Framework Moniker (TFM) to .NET 5.0. In my case, the value changes from <strong>net472</strong> to <strong>net5.0</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/3-Update-TFM.jpg" class="kg-image" alt="The .NET Upgrade Assistant updates the TFM" loading="lazy" width="1695" height="1035" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/3-Update-TFM.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/3-Update-TFM.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/3-Update-TFM.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/3-Update-TFM.jpg 1695w" sizes="(min-width: 720px) 720px"></figure><h3 id="update-nuget-packages">Update NuGet Packages</h3><p>Once the Upgrade Assistant updates the TFM, it attempts to update the project’s NuGet packages. The tool uses an analyzer to detect which references to remove and which packages to upgrade with their .NET 5 versions. Then, the tool updates the packages.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/4-Update-NuGet-Packages.jpg" class="kg-image" alt="The .NET Upgrade Assistant updates the NuGet packages" loading="lazy" width="2000" height="1436" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/4-Update-NuGet-Packages.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/4-Update-NuGet-Packages.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/4-Update-NuGet-Packages.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/4-Update-NuGet-Packages.jpg 2055w" sizes="(min-width: 720px) 720px"></figure><h3 id="add-template-files">Add Template Files</h3><p>After the tool updates any NuGet packages, it adds any relevant template files. ASP.NET Core uses template files for configuration and startup. These typically include <code>Program.cs</code>, <code>Startup.cs</code>, <code>appsettings.json</code>, and <code>appsettings.development.json</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/5-Add-Template-Files.jpg" class="kg-image" alt="The .NET Upgrade Assistant adds template files" loading="lazy" width="1817" height="1180" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/5-Add-Template-Files.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/5-Add-Template-Files.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/5-Add-Template-Files.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/5-Add-Template-Files.jpg 1817w" sizes="(min-width: 720px) 720px"></figure><h3 id="migrate-application-configuration-files">Migrate Application Configuration Files</h3><p>Now the tool is ready to migrate our application configuration files. The tool identifies what settings are supported, then migrates any configurable settings to my <code>appSettings.json</code> file. After that is complete, the tool migrates <code>system.web.webPages.razor/pages/namespaces</code> by updating <code>_ViewImports.cshtml</code> with an <code>@addTagHelper</code> reference to <code>Microsoft.AspNetCore.Mvc.TagHelpers</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/6-Convert-Namespaces.jpg" class="kg-image" alt="The .NET Upgrade Assistant migrates app config files" loading="lazy" width="1967" height="1122" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/6-Convert-Namespaces.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/6-Convert-Namespaces.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/6-Convert-Namespaces.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/6-Convert-Namespaces.jpg 1967w" sizes="(min-width: 720px) 720px"></figure><h3 id="update-c-source">Update C# Source</h3><p>Now, the .NET Upgrade Assistant upgrades C# code references to their .NET Core counterparts. You’ll see several steps listed in the terminal—not all apply. In those cases, they’ll be skipped over and flagged as <code>[Complete]</code>.</p><p>In my case, the step first removes any <code>using</code> statements that reference .NET Framework namespaces, like <code>System.Web</code>. Then, it ensures my <code>ActionResult</code> calls come from the <code>Microsoft.AspNetCore.Mvc</code> namespace. Finally, the Upgrade Assistant  ensures that I don’t use <code>HttpContext.Current</code>, which ASP.NET Core doesn’t support.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/7-Update-Source.jpg" class="kg-image" alt="The .NET Upgrade Assistant updates the C# source" loading="lazy" width="2000" height="1057" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/7-Update-Source.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/7-Update-Source.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/7-Update-Source.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/7-Update-Source.jpg 2245w" sizes="(min-width: 720px) 720px"></figure><p>The final step is to evaluate the next project. Since our solution only has one project, the tool exits.</p><h2 id="manually-fix-remaining-issues">Manually Fix Remaining Issues</h2><p>As you head back to your project, you’ll see build errors. This is normal. This tool will automate a lot of the migration for you, but you’ll still need to tidy some things up. A majority of these issues involve how ASP.NET Core handles startup, configuration, and bundling.</p><ul><li>The <code>Global.asax</code> and <code>Global.asax.cs</code> files are no longer needed in ASP.NET Core, as the global application event model is replaced with ASP.NET Core’s dependency injection model, in <code>Startup.cs</code>.</li><li>You won’t need the <code>App_Start</code> folder or any of the files in it (<code>BundleConfig.cs</code>, <code>FilterConfig.cs</code>, and <code>RouteConfig.cs</code>). Go ahead and delete it. Feels good, doesn’t it?</li><li>After you do this, most of your remaining errors are related to the bundling of your static assets. ASP.NET Core works with several bundling solutions. Read the <a href="https://docs.microsoft.com/aspnet/core/migration/mvc?view=aspnetcore-5.0&preserve-view=true&ref=daveabrock.com#configure-bundling-and-minification">bundling documentation</a> and choose what works best for your project.</li><li>Finally, fix any issues that remain. Your mileage may vary, but my changes were minimal. For example, in my <code>_Layout.cshtml</code> file, I had to inject an <code>IHttpContextAccessor</code> to access the <code>HttpContext.Session</code> and I also needed to clean up some <code>ActionResult</code> responses.</li></ul><h2 id="extending-the-net-upgrade-assistant">Extending the .NET Upgrade Assistant</h2><p>While the Upgrade Assistant fulfills most of your use cases, it has <a href="https://github.com/dotnet/upgrade-assistant/blob/main/docs/extensibility.md?ref=daveabrock.com">an <em>optional</em> accessibility model</a> that allows you to customize upgrade steps without modifying the tool yourself. For example, you can explicitly map NuGet packages to their replacements, add custom template files, and add custom upgrade steps. To get started, you’ll include an <code>ExtensionManifest.json</code> file that defines where the tool finds the different extension items. You need a manifest, but all of the following elements are optional, so you can define only what you need.</p><pre><code>{
  "ExtensionName": "My awesome extension",

  "PackageUpdater": {
    "PackageMapPath": "PackageMaps"
  },
  "TemplateInserter": {
    "TemplatePath": "Templates"
  },

  "ExtensionServiceProviders": [
    "MyAwesomeExtension"
  ]
}
</code></pre><p>When you run the Upgrade Assistant, you can pass an <code>-e</code> argument to pass the location of the manifest file, or define an <code>UpgradeAssistantExtensionPaths</code> environment variable. Check out <a href="https://github.com/dotnet/upgrade-assistant/blob/main/docs/extensibility.md?ref=daveabrock.com">the documentation</a> for details.</p><p>Do you remember when we manually deleted the <code>Global.asax</code> and the contents of the <code>App_Start</code> folder? If we’re upgrading many projects, consider adding a custom upgrade step to delete these.</p><h2 id="learn-more">Learn More</h2><p>As I mentioned, the .NET Upgrade Assistant is a promising and powerful tool—however, it’s in prerelease mode and is quickly evolving. Make sure to check out the tool’s GitHub repository to get up to speed and <a href="https://github.com/dotnet/upgrade-assistant/blob/main/docs/roadmap.md?ref=daveabrock.com">report any issues or suggestions</a>. You can also <a href="https://github.com/dotnet/upgrade-assistant/blob/main/docs/roadmap.md?ref=daveabrock.com">review the tool’s roadmap</a>.</p><p>Stay tuned for improvements.  For example, .NET 5 is a “Current” release—this means it’s supported for 3 months after .NET 6 officially ships (the support ends in February 2022). .NET 6, to be released this November, is a Long Term Support (LTS) release—meaning it’s supported for a minimum of 3 years.  As a result, you’ll soon see the ability to <a href="https://github.com/dotnet/upgrade-assistant/issues/95?ref=daveabrock.com">choose which release to target</a>.</p><h2 id="conclusion">Conclusion</h2><p>In this article, we toured the new .NET Upgrade Assistant and showed how to speed up your migration to .NET 5. Have you tried it? Leave a comment and let me know what you think.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #45: 🔥 At last, hot reload is (initially) here ]]></title>
        <description><![CDATA[ Hey, hot reload is here! We also talk about C# updates. ]]></description>
        <link>https://www.daveabrock.com/2021/04/17/dotnet-stacks-45/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 16 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/04/THE-.NET-STACKS-1.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li><strong>One big thing</strong>: .NET 6 Preview 3 is here, and so is hot reload</li><li><strong>The little thing</strong>: C# updates</li><li>Last week in the .NET world</li></ul><hr><h1 id="-net-6-preview-3-is-here-and-so-is-hot-reload">.NET 6 Preview 3 is here, and so is hot reload</h1><p>On Thursday, Microsoft rolled out .NET 6 Preview 3. Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3/?ref=daveabrock.com">has the announcement covered</a>. As he notes in the post, the release is “dedicated almost entirely to low-level performance features.” For example, we’ve got <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3/?ref=daveabrock.com#faster-handling-of-structs-as-dictionary-values">faster handling of structs as Dictionary values</a>, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3/?ref=daveabrock.com#faster-interface-checking-and-casting">faster interface checking and casting thanks to the use of pattern matching</a>, and <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3/?ref=daveabrock.com#runtime-codegen">code generation improvements</a>. The team <a href="https://devblogs.microsoft.com/nuget/net-5-nuget-restore-failures-on-linux-distributions-using-nss-or-ca-certificates/?ref=daveabrock.com">resolved an issue</a> where NuGet restore failed on Linux thanks to previous certificate issues. There were also updates to <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0-preview.3.21201.2?ref=daveabrock.com">EF Core</a> and <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0-preview.3.21201.2?ref=daveabrock.com">ASP.NET Core</a>.</p><p>Oh, and <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3/?ref=daveabrock.com#initial-net-hot-reload-support">initial hot reload support</a> is finally here.</p><p>Hot reload isn’t just for Blazor developers to enjoy—it’s built into the .NET 6 runtime. With Preview 3, you can use it by running <code>dotnet watch</code> in your terminal with ASP.NET Core web apps—Razor Pages, MVC, and Blazor (Server and WebAssembly). In future updates, you’ll enjoy Visual Studio support and use it with other project types like mobile, console apps, and client and mobile apps.</p><p>It’s been highly requested, and for a good reason—front-end frameworks and libraries based on interpreted languages like JS have enjoyed this for the last five years, and it’s a fantastic productivity booster. It’s easy to rag on Microsoft for taking this long—but they’ve had more significant problems during this time. Five years ago, Microsoft was preparing the roll out of the first version of .NET Core, and a component library like Blazor was just a thought, if at all. Now, the runtime is ready to address these issues (as it’s <a href="https://github.com/dotnet/core/issues/5510?ref=daveabrock.com">a main goal</a> of .NET 6).</p><p>I tried out hot reload with Blazor Server this weekend (a blog post is coming). I’ll include some GIFs that show what it’s like.</p><p>Here’s basic editing of static text:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-hello-friends.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>Here’s what happens when I update C# code:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-increment-by-5.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>In the following example, you’ll see here that it preserves state. When I change the <code>currentCount</code> value, the state of the component is maintained. I’ll need to refresh the page to see the new <code>currentCount</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-preserve-state.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>Here’s where I put it all together by dropping in components (with independent state) and editing some CSS for good measure.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-put-it-together.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>However, <a href="https://docs.microsoft.com/visualstudio/debugger/supported-code-changes-csharp?ref=daveabrock.com">not all code actions are supported</a>. When this happens—like renaming a method—it will revert to current <code>dotnet watch</code> behavior by recompiling and refreshing your page with the latest bits.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-method-rename.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>If you have runtime errors, a banner displays at the top with the appropriate information. When you resolve your issues, the app will recompile and refresh.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/04/hr-build-error.gif" class="kg-image" alt loading="lazy" width="1920" height="1022"></figure><p>On the subject of Blazor, Preview 3 <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3/?ref=daveabrock.com#blazorwebview-controls-for-wpf-windows-forms">ships with a <code>BlazorWebView</code> control</a>. This allows WPF and Windows Forms developers to embed Blazor functionality into existing .NET 6 desktop apps.</p><hr><h1 id="the-little-thing-c-updates">The little thing: C# updates</h1><p>Last week, Bill Wagner <a href="https://devblogs.microsoft.com/dotnet/announcing-open-source-c-standardization-standards/?ref=daveabrock.com">announced open-source C# standardization</a>. In addition to the compiler work repo (in dotnet/roslyn) and the repo for C# language evolution (dotnet/csharplang), there is now a new repo (dotnet/csharpstandard) dedicated to documenting the standard for the latest C# language versions.</p><p>The new repo sits under the .NET Foundation, and as Wagner states:</p><blockquote>Moving the standards work into the open, under the .NET Foundation, makes it easier for standardization work. Everything from language innovation and feature design through implementation and on to standardization now takes place in the open. It will be easier to ask questions among the language design team, the compiler implementers, and the standards committee. Even better, those conversations will be public … The end result will be a more accurate standard for the latest versions of C#.</blockquote><p>If you’re having trouble distinguishing between dotnet/csharplang and dotnet/csharpstandard, <a href="https://devblogs.microsoft.com/dotnet/announcing-open-source-c-standardization-standards/?ref=daveabrock.com#comment-8901">you aren’t alone</a>. Bill Wagner notes that <a href="https://devblogs.microsoft.com/dotnet/announcing-open-source-c-standardization-standards/?ref=daveabrock.com#comment-8902">there’s some overlap between the repos</a>, and it’s a work in progress.</p><p>Speaking of C#, it’s nice to check out any <a href="https://github.com/dotnet/csharplang/tree/main/proposals?ref=daveabrock.com">language proposals</a> from time-to-time, and <a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/file-scoped-namespaces.md?ref=daveabrock.com">file-scoped namespaces</a> is making progress as a C# 10 proposal.</p><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><p></p><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3?ref=daveabrock.com">announces .NET 6 Preview 3</a>, and Dan Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3?ref=daveabrock.com">shows off the ASP.NET Core updates in .NET 6 Preview 3</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=U6cwOzUqjxY&ref=daveabrock.com">has a C# roundtable</a> with C# gods Mads Torgersen, Bill Wagner, and Jon Skeet.</li><li>The NuGet team addresses <a href="https://devblogs.microsoft.com/nuget/net-5-nuget-restore-failures-on-linux-distributions-using-nss-or-ca-certificates?ref=daveabrock.com">restore failures on Linux distributions using NSS or ca-certificates</a>, and Nikolche Kolev <a href="https://devblogs.microsoft.com/visualstudio/performance-improvements-in-nuget?ref=daveabrock.com">writes about NuGet performance improvements</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Microsoft announces <a href="https://devblogs.microsoft.com/java/announcing-preview-of-microsoft-build-of-openjdk?ref=daveabrock.com">a preview of their own OpenJDK build</a>.</li><li>Jorge Garcia Hirota <a href="https://devblogs.microsoft.com/azure-sdk/communication-services-ga?ref=daveabrock.com">announces GA client libraries for Azure Communication Services</a>.</li><li>Dapr v1.1.0 <a href="https://blog.dapr.io/posts/2021/04/02/dapr-v1.1.0-is-now-available/?ref=daveabrock.com">is now available</a>.</li><li>The AWS SDK for .NET version 1 <a href="https://aws.amazon.com/blogs/developer/aws-sdk-for-net-version-1-has-reached-the-end-of-support/?ref=daveabrock.com">has reached the end of support</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/my-new-book-aspnetcore-in-action-2e-is-available-now/?ref=daveabrock.com">announces the second edition of his book, ASP.NET Core in Action</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Bill Wagner <a href="https://devblogs.microsoft.com/dotnet/announcing-open-source-c-standardization-standards?ref=daveabrock.com">announces open-source C# standardization</a>.</li><li>For community standups: Languages &amp; Runtime <a href="https://www.youtube.com/watch?v=Rksr7XzyOPA&ref=daveabrock.com">discusses C# standardization</a>, Entity Framework <a href="https://www.youtube.com/watch?v=GhIhwCafilk&ref=daveabrock.com">talks about Azure SQL</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=kF-su6ejbBI&ref=daveabrock.com">discusses Microsoft Identity</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Kevin W. Griffin asks: <a href="https://consultwithgriff.com/signalr-message-guarantee-deliverability/?ref=daveabrock.com">does SignalR guarantee message deliverability?</a></li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/04/07/blazor-static-images/?ref=daveabrock.com">works on static images in Blazor</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/04/08/blazor-dynamic-component?ref=daveabrock.com">works with DynamicComponent in Blazor</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/create-zip-files-on-http-request-without-intermediate-files-using-aspdotnet-mvc-framework?ref=daveabrock.com">creates ZIP files on HTTP request without intermediate files using the ASP.NET MVC framework</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/tetris-in-blazor-part-3-tetrominos/?ref=daveabrock.com">continues building his Tetris app in Blazor</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/04/05/creating-verifiable-credentials-in-asp-net-core-for-decentralized-identities-using-trinsic/?ref=daveabrock.com">creates verifiable credentials in ASP.NET Core for decentralized identities using Trinsic</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/creating-blazor-material-navigation-menu/?ref=daveabrock.com">creates a Blazor nav menu using Material UI</a>.</li><li>Sam Xu <a href="https://devblogs.microsoft.com/odata/attribute-routing-in-asp-net-core-odata-8-0-rc?ref=daveabrock.com">writes about attribute routing in ASP.NET Core OData 8.0 RC</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/blazor-wasm-404-error-and-fix-for-github-pages/?ref=daveabrock.com">troubleshoots a 404 issue when deploying Blazor Web Assembly to GitHub Pages</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>David Hayden <a href="https://www.davidhayden.me/blog/install-net5-on-ubuntu-20-04?ref=daveabrock.com">installs .NET on Ubuntu</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/getting-started-uno-platform/?ref=daveabrock.com">gets started with the Uno platform</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/moving-to-desktop-applications-dotnet-core-dotnet-5?ref=daveabrock.com">writes about moving to desktop applications in .NET 5</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/secret-management-in-dotnet-applications/?ref=daveabrock.com">writes about secrets management in .NET apps</a>.</li><li>Sergey Tihon <a href="https://sergeytihon.com/2021/04/05/dotnet-watch-with-microsoft-identity-web-or-custom-idistributedcache/?ref=daveabrock.com">configures dotnet watch with Microsoft.Identity.Web or custom IDistributedCache</a>.</li><li>Tom Deseyn <a href="https://developers.redhat.com/blog/2021/04/06/c-9-pattern-matching/?ref=daveabrock.com">writes about C# 9 pattern matching</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>GitHub explains <a href="https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/?ref=daveabrock.com">their new authentication token formats</a>, and also walks us through <a href="https://github.blog/2021-04-05-how-we-scaled-github-api-sharded-replicated-rate-limiter-redis/?ref=daveabrock.com">how they scaled the GitHub API with a rate limiter in Redis</a>.</li><li>John Bohannon <a href="https://devblogs.microsoft.com/devops/building-your-first-github-action?ref=daveabrock.com">shows you how to write your first GitHub Action</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/azure-functions-not-loading-my-dependencies-what-have-i-missed?ref=daveabrock.com">works through why Azure Functions doesn’t load his dependencies</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/local-development-with-azure-service-bus/?ref=daveabrock.com">writes about local development with the Azure Service Bus</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/04/03/service-bus-batching-and-pre-fetch/?ref=daveabrock.com">writes about batching and pre-fetching with Azure Service Bus</a>.</li><li>Laurent Kempé <a href="https://laurentkempe.com/2021/04/06/accessing-dapr-secrets-building-block-using-dapr-dotnet-sdk/?ref=daveabrock.com">accesses the Dapr secrets building block using the Dapr .NET SDK</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Michael Washington <a href="https://blazorhelpwebsite.com/ViewBlogPost/49?ref=daveabrock.com">creates Power BI paginated reports with Blazor</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/recursive-data-with-entity-framework-core-and-sql-server?ref=daveabrock.com">writes about recursive Data With Entity Framework Core and SQL Server</a> and also <a href="https://khalidabuhakmeh.com/modeling-most-sql-relationships-in-entity-framework-core?ref=daveabrock.com">models SQL relationships in EF Core</a>.</li><li>Mark Heath <a href="https://markheath.net/post/azure-functions-bicep?ref=daveabrock.com">deploys an Azure Function app with Bicep</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/take-your-windows-terminal-and-powershell-to-the-next-level-with-terminal-icons?ref=daveabrock.com">adds more icons to Windows Terminal</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Leomaris Reyes <a href="https://blog.logrocket.com/getting-started-with-collectionview-in-xamarin-forms/?ref=daveabrock.com">gets started with CollectionView</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-3?ref=daveabrock.com">provides another MAUI update</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Jay Krishna Reddy <a href="https://www.c-sharpcorner.com/article/unit-testing-using-xunit-and-moq-in-asp-net-core/?ref=daveabrock.com">unit tests using XUnit And Moq in ASP.NET Core</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/smarter-single-page-application-with-a-rest-api/?ref=daveabrock.com">develops smarter SPAs with REST APIs</a>.</li><li>Scott Hannen <a href="https://scotthannen.org/blog/2021/04/07/integration-test-experiment-1.html?ref=daveabrock.com">experiments experiments with making integration tests easier to write</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/implementing-a-domain-with-poco-plain-old-clr-objects/?ref=daveabrock.com">implements a domain with POCOs</a>.</li><li>Nish Anil <a href="https://devblogs.microsoft.com/aspnet/your-top-dotnet-microservices-questions-answered?ref=daveabrock.com">answers .NET microservices questions</a>.</li><li>Tobias Günther <a href="https://stackoverflow.blog/2021/04/05/a-look-under-the-hood-how-branches-work-in-git/?ref=daveabrock.com">explains how branches work in Git</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-190-microservices-with-sean-whitesell/?ref=daveabrock.com">talks to Sean Whitesell about microservices</a>.</li><li>Scott Hanselman <a href="https://hanselminutes.simplecast.com/episodes/jean-yang-KS0GgL4x?ref=daveabrock.com">talks to Jean Yang about API observability</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-371-Cloud-Native-Machine-Learning?ref=daveabrock.com">talks about cloud-native machine learning</a>, and also <a href="http://azpodcast.azurewebsites.net/post/Episode-372-API-Management?ref=daveabrock.com">talks about the API Management service</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-063-use-cases-for-graphql-in-net/?ref=daveabrock.com">discusses use cases for GraphQL in .NET </a>.</li><li>The Complete Developer podcast <a href="https://completedeveloperpodcast.com/state-machines/?ref=daveabrock.com">talks about state machines</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/248?ref=daveabrock.com">talks about satisfying business requirements</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/A-Journey-to-NET-MAUI?ref=daveabrock.com">talks about .NET MAUI</a>, and also <a href="https://www.youtube.com/watch?v=H_pqfeRgTYw&ref=daveabrock.com">creates .NET project templates</a>.</li><li>The AzureFunBytes stream <a href="https://devblogs.microsoft.com/devops/azurefunbytes-intro-to-cosmos-db-with-mark-brown?ref=daveabrock.com">talks to Mark Brown about Cosmos DB</a>.</li><li>Steve Collins <a href="https://blog.jetbrains.com/dotnet/2021/04/09/net-5-dependency-injection-webinar-recording/?ref=daveabrock.com">talks to JetBrains about dependency injection</a>.</li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/XAML-Hot-Reload-Updates--Xamarin-Show?ref=daveabrock.com">discusses XAML hot reload updates</a>.</li><li>At Technology and Friends, <a href="https://www.davidgiard.com/2021/04/05/TedNewardOnTechnologyCulture.aspx?ref=daveabrock.com">David Giard talks to Ted Neward about technology culture</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Get-Started-with-the-New-Database-Migration-Guides-to-Migrate-Your-Databases-to-Azure?ref=daveabrock.com">talks about migrating databases to Azure</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Instant Feedback Is Here: Introducing Hot Reload in .NET 6 ]]></title>
        <description><![CDATA[ With .NET 6 Preview 3, you can use hot reloading with your ASP.NET Core apps. ]]></description>
        <link>https://www.daveabrock.com/2021/04/13/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 12 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1501290301209-7a0323622985?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fHF1aWNrfGVufDB8fHx8MTYxOTgyODIzMQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em><strong>NOTE</strong>: This post originally appeared on the <a href="https://www.telerik.com/blogs/instant-feedback-is-here-introducing-hot-reload-in-dotnet-6?ref=daveabrock.com">Progress Telerik Blog</a>.</em></p><p>With .NET 6—and its release officially going live in November 2021—a big focus is <a href="https://github.com/dotnet/core/issues/5510?ref=daveabrock.com">improving developer inner-loop performance</a>. The idea of inner-loop performance comes down to this: when I make a code change, how quickly can I see it reflected in my application?</p><p>With .NET Core, you can do better than the traditional save-build-run workflow <a href="https://docs.microsoft.com/aspnet/core/tutorials/dotnet-watch?view=aspnetcore-5.0&ref=daveabrock.com">with <code>dotnet watch</code></a>. The tool can watch for your source files to change, then trigger compilation. When running <code>dotnet watch</code> against your ASP.NET Core web apps—for MVC, Blazor, or Razor Pages—you still need to wait for recompilation and your app to reload. If you do this repeatedly throughout the day, sitting and waiting can become frustrating. Waiting 10 seconds one time doesn’t seem like a huge deal. If you do this 100 times a day, you’re killing almost 17 minutes waiting for your app to reload!</p><p>Developers in other ecosystems—especially in the front-end space—are familiar with the concept of hot reloading: you save a file, and the change appears almost instantaneously. Once you work with hot reloading, it’s tough to go back. As the .NET team tries to attract outsiders and new developers (<a href="https://github.com/dotnet/core/issues/5465?ref=daveabrock.com">another goal for the .NET 6 release</a>), not having this feature can be a non-starter to outsiders, even considering all the other wonderful capabilities a mature framework like .NET has to offer. (Not to mention that the insiders have been impatiently waiting for this for quite some time, too.)</p><p>The wait is finally over! Starting with .NET 6 Preview 3, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3/?ref=daveabrock.com#initial-net-hot-reload-support">you can use hot reload</a> with your ASP.NET Core applications—including Blazor (both Blazor Server and Blazor WebAssembly), Razor Pages, and MVC. You can see hot reloading for static assets like CSS and compiled C# code as well.</p><p>In this post, I’ll show you how it works with a Blazor Server application. Hot reload currently only works with running <code>dotnet watch</code> from your terminal. In future previews, you’ll see Visual Studio integration and support for client and mobile applications.</p><h2 id="how-to-use-hot-reload-today">How to Use Hot Reload Today</h2><p>To try out hot reload today, you’ll first need to install <a href="https://dotnet.microsoft.com/download/dotnet/6.0?ref=daveabrock.com">the latest .NET 6 preview SDK</a> (at the time of this post, it’s <em>SDK 6.0.100-preview.3</em>). You’ll need to do this whether or not you have the latest Visual Studio 2019 bits installed. It’ll be a few months before the .NET 6 preview updates are in sync with Visual Studio updates.</p><p>Once you’ve installed the latest .NET 6 preview SDK, update your profile in your <code>Properties/launchSettings.json</code> file to one of the following.</p><ul><li>Blazor Server, MVC, and Razor Pages: <code>"hotReloadProfile": "aspnetcore"</code></li><li>Blazor WebAssembly: <code>"hotReloadProfile": "blazorwasm"</code></li></ul><p>Since I’m using Blazor Server, my profile looks like the following.</p><pre><code class="language-json">"profiles": {
    "HotReloadDotNet6": {
      "commandName": "Project",
      "dotnetRunMessages": "true",
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "hotReloadProfile": "aspnetcore"
    }
  }
</code></pre><h2 id="basic-usage">Basic Usage</h2><p>To start, let’s change the heading of our <code>Index</code> component and see how quickly the reload occurs—it seems instantaneous.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-hello-friends.gif" class="kg-image" alt="Change the heading text to see hot reload in action" loading="lazy" width="1920" height="1022"></figure><p>It’s great that it’s fast, but that’s not very exciting. I just changed static text. What about changing the code that previously required recompilation of our application? In the <code>Counter</code> component, I’m going to increase the count by five every time a user clicks the button. You’ll see the change occurs just as fast.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-increment-by-5.gif" class="kg-image" alt="Update C# code to see the instant feedback" loading="lazy" width="1920" height="1022"></figure><p>What happens when we are working with user state? For example, if I am in the middle of a user interaction and change the app, will that interaction be reset? In my previous example, I clicked the <code>Counter</code> component’s button until the count reached a value of 20. If I change the <code>currentCount</code> from <code>0</code> to <code>10</code>, will things reset?</p><p>The answer is no—the state is independently preserved! Watch as I continue increasing the counter. When I refresh the page, my counter starts at 10, as I’d expect.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-preserve-state.gif" class="kg-image" alt="Hot reload preserves a component's state" loading="lazy" width="1920" height="1022"></figure><p>As we put it all together, watch how I can add multiple components with their own state and modify CSS—all with the instant feedback that hot reloading provides.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-put-it-together.gif" class="kg-image" alt="Hot reload allows me to iterate quickly" loading="lazy" width="1920" height="1022"></figure><h2 id="working-with-errors">Working with Errors</h2><p>You might be wondering what happens when <code>dotnet watch</code> encounters runtime exceptions or build errors. Will it exit and decorate my screen with a stack trace? To try this out, let me fat-finger a variable name by changing the iterator to <code>currentCounts</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-method-rename.gif" class="kg-image" alt="Hot reload handles errors gracefully" loading="lazy" width="1920" height="1022"></figure><p>When this happens, you’ll see a red banner at the top of the page. It includes the specific error message and where it occurs. When I fix the error, a rebuild occurs. It isn’t instantaneous, but it works well—most times, you don’t have to shut down and restart the application.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-build-error-fix.gif" class="kg-image" alt="When I resolve my error, a rebuild occurs" loading="lazy" width="1920" height="1022"></figure><h2 id="what-are-the-limitations">What Are the Limitations?</h2><p>When you initially use <code>dotnet watch</code> with hot reload, your terminal will display the following message:</p><pre><code>Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload. Press "Ctrl + R" to restart.
</code></pre><p>That link is <a href="https://aka.ms/dotnet/hot-reload?ref=daveabrock.com">worth checking out</a> to see which changes are supported. With a few exceptions, most of these changes are supported.</p><ul><li>Types</li><li>Iterators</li><li>Async/await expressions</li><li>LINQ expressions</li><li>Lambdas</li><li>Dynamic objects</li></ul><p>As for the unsupported changes, here are a few of the major ones:</p><ul><li>Renaming elements</li><li>Deleting namespaces, types, and members</li><li>Adding or modifying generics</li><li>Modifying interfaces</li><li>Modifying method signatures</li></ul><p>When you make a change that hot reload doesn’t support, it’ll fall back to typical <code>dotnet watch</code> behavior. Your app will recompile and reload in your browser. For example, this occurs when I rename my method from <code>IncrementCount</code> to <code>IncrementCounts</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hr-build-error-1.gif" class="kg-image" alt="When hot reload isn't supported, it falls back" loading="lazy" width="1920" height="1022"></figure><h2 id="conclusion">Conclusion</h2><p>In this post, I introduced hot reload functionality that is new in .NET 6 Preview 3. I discussed how to use it today, and how it handles various development scenarios. I also discussed which changes are unsupported.</p><p>While Blazor receives a lot of fanfare in ASP.NET Core, it’s important to note that this benefits the entire .NET ecosystem. For example, you can use this now with Razor Pages and MVC—and you’ll soon see support with client and mobile apps as well. Give it a shot today, and let me know what you think!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #44: 🐦 APIs that are light as a feather ]]></title>
        <description><![CDATA[ This week, we discuss the FeatherHttp project and Azure Static Web Apps. ]]></description>
        <link>https://www.daveabrock.com/2021/04/10/dotnet-stacks-44/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 09 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li><strong>One big thing</strong>: Looking at the FeatherHttp project</li><li><strong>The little things</strong>: Azure Static Web apps with DevOps, new OSS badges, coding tip</li><li>Last week in the .NET world</li></ul><hr><h1 id="one-big-thing-looking-at-the-featherhttp-project">One big thing: Looking at the FeatherHttp project</h1><p>We’ve talked in the past about ASP.NET Core MVC APIs and their role in the .NET Core ecosystem. While MVC has received performance improvements and does what it sets out to do, it carries a lot of overhead and is often reminiscent of the “here you go, have it all” reputation of .NET Framework. It’s a robust solution that allows you to build complex APIs but comes with a lot of ceremony. With imperative frameworks like Go and Express, you can get started immediately and with little effort. No one has said the same about writing APIs in ASP.NET Core. It’s a bad look on the framework in general, especially when folks want to try out .NET for the first time.</p><p>Last year, Dapr pushed cross-platform samples for the major frameworks, and this tweet shows a common theme with MVC:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">It does a *REALLY* bad job at showing off C#. The example has 20+ files while all the others have 2-5 🤦‍♂️</p>&mdash; Kristian Hellang (@khellang) <a href="https://twitter.com/khellang/status/1198530726100164608?ref_src=twsrc%5Etfw&ref=daveabrock.com">November 24, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Can we have solutions that allow you to get started quickly and avoid this mess? What if you aren’t a fan of controllers? You could use external libraries like <a href="https://github.com/jbogard/MediatR?ref=daveabrock.com">MediatR</a> or <a href="https://github.com/ardalis/ApiEndpoints?ref=daveabrock.com">API Endpoints</a>, or a <a href="https://nancyfx.org/?ref=daveabrock.com">framework like Nancy</a>—but it still feels like the native runtime deserves better. The ASP.NET Core team has <a href="https://twitter.com/davidfowl/status/1198870972679372800?ref=daveabrock.com">thought about this</a> for a while.</p><p>The <a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com">route-to-code alternative</a> is a great start, which <a href="https://daveabrock.com/2020/12/04/migrate-mvc-to-route-to-code?ref=daveabrock.com">I wrote about</a>. It allows you to write simple JSON APIs, using an API endpoints model—with some helper methods that lend a hand.</p><p>Here’s a quick example:</p><pre><code class="language-csharp">app.UseEndpoints(endpoints =&gt;
{
    endpoints.MapGet("/hello/{name:alpha}", async context =&gt;
    {
        var name = context.Request.RouteValues["name"];
        await context.Response.WriteAsJsonAsync(new { message = $"Hello {name}!" });
    });
});
</code></pre><p>It’s great, but Microsoft will tell you it’s only for simple APIs. Their docs <a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com#notable-missing-features-compared-to-web-api">clearly state</a>: <em>Route-to-code is designed for basic JSON APIs. It doesn’t have support for many of the advanced features provided by ASP.NET Core Web API.</em> This begs the question: will .NET ever have a modern, lightweight API solution that has a low barrier to entry and also scales? Can I have a lightweight API that starts small and allows me to add complex features as I need them?</p><p>That is the goal of <a href="https://github.com/featherhttp/framework?ref=daveabrock.com">FeatherHttp</a>, a project from ASP.NET Core architect David Fowler. Triggered by Kristian’s tweet, Fowler says the repo has three key goals: to be built on the same primitives on .NET Core, to be optimized to build HTTP APIs quickly, and having the ability to take advantage of existing .NET Core middleware and frameworks. According to a <a href="https://github.com/featherhttp/framework/issues/3?ref=daveabrock.com#issuecomment-564403379">GitHub comment</a>, the solution uses 90% of ASP.NET Core and changes the Startup pattern to be more lightweight. You can also <a href="https://github.com/featherhttp/tutorial?ref=daveabrock.com">check out a tutorial</a> that walks you through building the backend of a React app with basic CRUD APIs and some serialization.</p><p>Here’s an example:</p><pre><code class="language-csharp">using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

var app = WebApplication.Create(args);

app.MapGet("/", async http =&gt;
{
    await http.Response.WriteAsync("Hello World");
});

await app.RunAsync();
</code></pre><p>Is this a fun experiment (currently at version <em>0.1.82-alpha</em>) or will it make its way into ASP.NET Core? I’m not a mind reader, my friends, but I do know two things: (1) David Fowler is the partner architect on ASP.NET Core, and (2) big objectives for .NET 6 are <a href="https://github.com/dotnet/core/issues/5465?ref=daveabrock.com">to appeal to new folks</a> and to <a href="https://github.com/dotnet/core/issues/5510?ref=daveabrock.com">improve the developer inner-loop experience</a>. I suspect we’ll be hearing a lot more about this. Stay tuned.</p><hr><h1 id="the-little-things-azure-static-web-apps-with-devops-new-oss-badges-code-complexity-tip">The little things: Azure Static Web apps with DevOps, new OSS badges, code complexity tip</h1><p>Last week, Microsoft announced that Azure Static Web Apps supports deployment through Azure DevOps YAML pipelines. I <a href="https://daveabrock.com/2021/04/01/static-web-apps-azure-pipelines?ref=daveabrock.com">wrote about it as well</a>. It opens doors for many corporate customers who aren’t ready to move to GitHub yet—while they’ve made great strides, GitHub still has some work to do to match the robust enterprise capabilities of Azure DevOps.</p><p>I was able to move one of my projects over seamlessly. Unlike GitHub Actions, Azure DevOps handles PR triggers for you automatically, so my YAML is pretty clean:</p><pre><code class="language-yaml">trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: AzureStaticWebApp@0
    inputs:
      app_location: "BlastOff.Client"
      api_location: "BlastOff.Api"
      output_location: "wwwroot"
    env:
      azure_static_web_apps_api_token: $(deployment_token)
</code></pre><p>While it isn’t as streamlined and elegant as the GitHub experience—you need to configure your deployment token manually, and you don’t get automatic staging environments—this should help improve adoption. If you’re wondering whether to use Azure Static Web Apps with Azure DevOps or GitHub, <a href="https://daveabrock.com/2021/04/01/static-web-apps-azure-pipelines?ref=daveabrock.com#should-i-use-azure-static-web-apps-with-azure-devops-or-github">I’ve got you covered</a>.</p><hr><p>The ASP.NET Core team <a href="https://twitter.com/ben_a_adams/status/1376587282413711364?ref=daveabrock.com">has introduced</a> “good first issue” and “Help wanted” GitHub badges. If you’ve ever wanted to contribute to ASP.NET Core but didn’t know where to start, this might help.</p><hr><p>Sometimes, it seems that processing a collection of objects is half of a developer’s job. It can often be a subject of abuse, especially when it comes to nested loops and their poor performance.</p><p>Here’s an example of me iterating through a list of <code>Blogger</code> objects, checking if a <code>Url</code> exists, and adding it to a list. (I’m using <a href="https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records?ref=daveabrock.com">records</a> and <a href="https://daveabrock.com/2020/07/14/c-sharp-9-target-typing-covariants?ref=daveabrock.com#improved-target-typing">target-typed expressions</a> for brevity.)</p><pre><code class="language-csharp">using System.Collections.Generic;

var result = new List&lt;string&gt;();
var bloggers = new List&lt;Blogger&gt;
{
    new("Dave Brock", "https://daveabrock.com", true),
    new("James Clear", "https://jamesclear.com", false)
};

foreach (var blogger in bloggers)
{
    if (blogger.IsTechBlogger)
    {
        var url = blogger.Url;
        if (url is not null)
            result.Add(url);
    }
}

record Blogger(string Name, string Url, bool IsTechBlogger);
</code></pre><p>Instead, try a <a href="https://www.martinfowler.com/articles/refactoring-pipelines.html?ref=daveabrock.com">LINQ collection pipeline</a>:</p><pre><code class="language-csharp">using System.Collections.Generic;
using System.Linq;

var urlList = new List&lt;string&gt;();
var bloggers = new List&lt;Blogger&gt;
{
    new("Dave Brock", "https://daveabrock.com", true),
    new("James Clear", "https://jamesclear.com", false)
};

urlList = bloggers.Where(b =&gt; b.IsTechBlogger)
                  .Select(u =&gt; u.Url)
                  .Where(u =&gt; u is not null).ToList();

record Blogger(string Name, string Url, bool IsTechBlogger);
</code></pre><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-4">🔥 The Top 4</h2><ul><li>Nish Anil <a href="https://devblogs.microsoft.com/aspnet/monitoring-and-observability-in-cloud-native-asp-net-core-apps?ref=daveabrock.com">writes about monitoring and observability in cloud-native ASP.NET Core apps</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/04/01/static-web-apps-azure-pipelines?ref=daveabrock.com">uses Azure Static Web Apps with Azure DevOps pipelines</a>.</li><li>Michael Shpilt <a href="https://michaelscodingspot.com/maximizing-the-power-of-logs-as-your-application-scales/?ref=daveabrock.com">maximizes the power of logs as applications scale</a>.</li><li>Vladimir Khorikov asks: <a href="https://enterprisecraftsmanship.com/posts/static-methods-evil/?ref=daveabrock.com">are static methods evil?</a></li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Azure Static Web Apps <a href="https://azure.microsoft.com/updates/public-preview-azure-static-web-apps-now-supports-deployment-with-azure-devops?ref=daveabrock.com">now supports deployment with Azure DevOps</a>.</li><li>GitHub Desktop <a href="https://github.blog/2021-03-30-github-desktop-now-supports-cherry-picking/?ref=daveabrock.com">now supports cherry-picking</a>.</li><li>Alvin Ashcraft <a href="https://mailchi.mp/e7c5133c9388/learn-winui-3-book-and-ebook-now-available?e=0eceb6f972&_lrsc=3fe8d675-aafa-4cf2-a5af-e2b4de71c460&ref=daveabrock.com">has released his book on WinUI 3.</a>.</li><li>Nicholas Blumhardt <a href="https://nblumhardt.com/2021/03/serilog-expressions-2/?ref=daveabrock.com">announces Serilog Expressions 2.0</a>.</li><li>PostSharp 6.9 is live <a href="https://blog.postsharp.net/post/postsharp-6-9-visual-studio-tooling-performance-improvements.html?ref=daveabrock.com">with Visual Studio Tooling performance improvements</a>.</li><li>Andrew Clinick <a href="https://blogs.windows.com/windowsdeveloper/2021/03/29/announcing-project-reunion-0-5?ref=daveabrock.com">announces Project Reunion 0.5</a>.</li><li>.NET Standard 1.3 is <a href="https://aws.amazon.com/blogs/developer/net-standard-1-3-is-no-longer-supported-in-aws-sdk-for-net-version-3-7/?ref=daveabrock.com">no longer supported in AWS SDK for .NET version 3.7</a>.</li><li>David Guida’s <a href="https://www.opensleigh.net/?ref=daveabrock.com">OpenSleigh project</a> has been <a href="https://twitter.com/DavideGuida82/status/1376896675579449351?ref=daveabrock.com">sponsored by JetBrains</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Matt Lacey <a href="https://www.mrlacey.com/2021/03/here-i-made-way-to-navigate-between-any.html?ref=daveabrock.com">builds a Visual Studio extension to navigate between ANY files</a>.</li><li>For community standups: Xamarin <a href="https://www.youtube.com/watch?v=su3ntRjEN1I&ref=daveabrock.com">previews .NET 6 updates</a> and ASP.NET <a href="https://www.youtube.com/watch?v=xRlDuXJ3t08&ref=daveabrock.com">talks about 12-factor apps</a>.</li><li>Because NuGet stores download counts in Int32, in <a href="https://twitter.com/JamesNK/status/1377400586950172672?ref=daveabrock.com">80 weeks the NewtonSoft.Json package will overflow it</a>.</li><li>Microsoft Build <a href="https://www.zdnet.com/article/its-official-microsoft-build-will-be-may-25-to-27/?ref=daveabrock.com">will occur on May 25-27</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Matthew Jones <a href="https://exceptionnotfound.net/tetris-in-blazor-part-2-cells-the-grid-and-the-game-state/?ref=daveabrock.com">continues writing a Tetris game in Blazor</a>.</li><li>Mukesh Murugan builds a chat application <a href="https://codewithmukesh.com/blog/realtime-chat-application-with-blazor/?ref=daveabrock.com">with Blazor, Identity, and SignalR</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-digitalocean-app-platform?ref=daveabrock.com">deploys Blazor WebAssembly apps to DigitalOcean</a>.</li><li>Sundaram Subramanian <a href="https://www.c-sharpcorner.com/article/breadcrumbs-for-blazor-using-mudblazor/?ref=daveabrock.com">writes about using the MudBlazor library for breadcrumbs</a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/asp-net-core-user-secrets-and-secret-manager-tool?ref=daveabrock.com">works with ASP.NET Core user secrets and the Secret Manager tool</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/03/26/blazor-modal-dialog-component/?ref=daveabrock.com">writes a Blazor dialog component in .NET 5</a>, and also <a href="https://www.claudiobernasconi.ch/2021/03/31/blazor-css-handling/?ref=daveabrock.com">handles CSS in Blazor</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/blazor-material-ui-configuration-and-theme-customization/?ref=daveabrock.com">works with Material UI in Blazor</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/handling-aspnet-core-exceptions-with-exceptionhandler-middleware?ref=daveabrock.com">handles exceptions with ASP.NET Core ExceptionHandlerMiddleware </a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/the-future-of-windows-apps-demystified-17d1f9e325d1?ref=daveabrock.com">writes about the future of Windows apps</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/project-reunion-why-desktop-developers-care?ref=daveabrock.com">writes about Project Reunion</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Paul Michaels <a href="https://www.pmichaels.net/2021/03/27/azure-service-bus-auto-delete-on-idle/?ref=daveabrock.com">writes about auto-deleting Azure Service Bus messages when idle</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/building-mono-repositories-with-github-actions?ref=daveabrock.com">builds mono-repos with GitHub Actions</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/03/azure-rest-apis-postman-oauth2/?ref=daveabrock.com">works with Azure REST APIs with Postman’s OAuth 2.0 Provider</a>.</li><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-03-30-making-auth-simpler-for-static-web-app-apis/?ref=daveabrock.com">writes about simplifying auth for Azure Static Web App APIs</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Tom Deseyn <a href="https://developers.redhat.com/blog/2021/03/30/c-9-top-level-programs-and-target-typed-expressions/?ref=daveabrock.com">writes about C# 9 top-level programs and target-typed expressions</a>.</li><li>Shawn Wildermuth <a href="http://wildermuth.com/2021/03/28/Coding-Shorts-Demystifying-Bitwise-Operators-in-C?ref=daveabrock.com">demystifies bitwise operators in C#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Clyde D’Souza <a href="https://codeburst.io/fundamentals-of-github-actions-d35dc3102447?ref=daveabrock.com">explores GitHub Actions fundamentals</a>.</li><li>Richard Reedy <a href="https://www.telerik.com/blogs/jump-starting-migration-dotnet-core-with-upgrade-assistant?ref=daveabrock.com">writes about the .NET Upgrade Assistant</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/the-windows-terminal-made-better-with-the-command-palette-plus-multiple-actions-in-one-command?ref=daveabrock.com">writes about recent updates to the Windows Terminal</a>.</li><li>Julio Sampaio <a href="https://www.red-gate.com/simple-talk/dotnet/software-testing/load-stress-testing-net-apps-with-apache-jmeter/?ref=daveabrock.com">stress tests .ET apps with Apache JMeter</a>.</li><li>Yannick Reekmans <a href="https://techcommunity.microsoft.com/t5/microsoft-365-pnp-blog/add-developer-powershell-and-developer-command-prompt-for-visual/ba-p/2243078?ref=daveabrock.com">adds the Developer PowerShell and Developer Command Prompt for Visual Studio to Windows Terminal</a>.</li><li>James Montemagno <a href="https://montemagno.com/code-generation-from-xaml-in-visual-studio/?ref=daveabrock.com">explores code Generation from XAML in Visual Studio</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Luis Matos <a href="https://luismts.com/global-error-handling-xamarin-forms/?ref=daveabrock.com">handles global errors </a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/sands-of-maui-issue-2?ref=daveabrock.com">provides another MAUI update</a>.</li><li>James Montemagno <a href="https://montemagno.com/setting-up-an-m1-mac-for-xamarin-development/?ref=daveabrock.com">sets Up an M1 Mac for Xamarin development</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Jason Farrell <a href="https://jfarrell.net/2021/03/28/common-misconception-2-serverless-is-good-for-apis/?ref=daveabrock.com">addresses a misconception that serverless is good for APIs</a>.</li><li>James Shore <a href="https://www.jamesshore.com/v2/books/aoad2/test-driven_development?ref=daveabrock.com">writes about TDD</a>.</li><li>Oleksii Holubiev <a href="https://hackernoon.com/net-authentication-security-notes-a64w35fg?source=rss">writes about .NET authentication</a>.</li><li>Genevieve Michaels <a href="https://blog.trello.com/how-to-give-your-manager-feedback?ref=daveabrock.com">writes about providing feedback to your manager without being a jerk</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/rest-apis-for-microservices-beware/?ref=daveabrock.com">discusses the pitfalls of using REST APIs for microservices</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/8-books-to-improve-as-a-net-developer/?ref=daveabrock.com">writes about 8 books for .NET developers</a>.</li><li>Rossitza Fakalieva <a href="https://www.telerik.com/blogs/lets-give-some-unit-testing-love-to-csharp-8-9-features?ref=daveabrock.com">unit tests some C# 8 and 9 features</a>.</li><li>James Hickey writes about <a href="https://fusionauth.io/learn/expert-advice/identity-basics/making-sure-your-auth-system-scales/?ref=daveabrock.com">scaling your auth system</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-062-innocent-application-performance-monitoring-with-innocent-bindura-from-raygun/?ref=daveabrock.com">talks about application monitoring</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-189-reactive-ddd-with-vaughn-vernon/?ref=daveabrock.com">talks about reactive DDD with Vaughn Vernon</a>.</li><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-73-c-sharp-and-net-for-beginners-with-vijesh-salian/?ref=daveabrock.com">discusses C# and .NET for beginners with Vijesh Salian</a>.</li><li>The Complete Developer podcast <a href="https://completedeveloperpodcast.com/side-hustle-fails/?ref=daveabrock.com">talks about side hustle failures</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>Over at Ask the Expert, <a href="https://channel9.msdn.com/Shows/Ask-the-Expert/Ask-the-Expert-Hello-Brian-A-conversation-with-Dr-Brian-Kernighan-creator-of-hello-world?ref=daveabrock.com">a discussion with Dr. Brian Kernighan, the inventor of “Hello, World.”</a></li><li>The On .NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Integrating-PowerApps-with-NET-Web-APIs?ref=daveabrock.com">integrates PowerApps with .NET Web APIs</a>, <a href="https://www.youtube.com/watch?v=L5Fy1-CTCLo&ref=daveabrock.com">discusses the .NET Upgrade Assistant</a>, and <a href="https://www.youtube.com/watch?v=VLqdRpwniwk&ref=daveabrock.com">integrates PowerApps with .NET Web APIs</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=LgNc-IA8d1g&ref=daveabrock.com">discuss Microsoft Identity with Christos Matskas</a>.</li><li>The AI Show <a href="https://channel9.msdn.com/Shows/AI-Show/Extract-information-from-your-documents-with-new-capabilities-in-Form-Recognizer?ref=daveabrock.com">extracts information from documents with Form Recognizer</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Working with the Blazor DynamicComponent ]]></title>
        <description><![CDATA[ In this post, we discuss how to dynamically render components in Blazor using the new DynamicComponent. ]]></description>
        <link>https://www.daveabrock.com/2021/04/08/blazor-dynamic-component/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 07 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1542831371-29b0f74f9713?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGh0bWx8ZW58MHx8fHwxNjE5ODI4MzUx&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Blazor is a joy when you know what you’re rendering—this typically involves knowing your types at compile time. But what happens when you want to render your components dynamically, when you don’t know your types ahead of time?</p><p>You can do it in a variety of ways: you can iterate through components and use complex conditionals, use reflection, <a href="https://www.davidguida.net/how-to-render-a-dynamic-component-with-blazor/?ref=daveabrock.com">declare a bunch of <code>RenderFragment</code>s</a>, or even <a href="https://jonhilton.net/blazor-dynamic-components/?ref=daveabrock.com">build your own render tree</a>. It can get complicated when dealing with parameters and complex data graphs, and none of these solutions are any good, really.</p><p>With .NET 6 Preview 1, the ASP.NET Core team introduced a built-in Blazor component, DynamicComponent, that <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-1/?ref=daveabrock.com#dynamiccomponent">allows you to render a component specified by type</a>. When you bring in the component, you specify the <code>Type</code> and optionally a dictionary of <code>Parameters</code>.</p><p>You would declare the component like this:</p><pre><code>&lt;DynamicComponent Type="@myType" Parameters="@myParameterDictionary" /&gt;
</code></pre><p>The <code>DynamicComponent</code> has a variety of applications. I find it to be valuable when working with form data. For example, you can render data based on a selected value without having to iterate through possible types.</p><p>In this post, I’ll walk through how to use the <code>DynamicComponent</code> when a user selects a list from a drop-down list. I’ve got the repo <a href="https://github.com/daveabrock/DynamicComponentDemo?ref=daveabrock.com">out on GitHub</a> for reference.</p><p>(Also, a shout-out to Hasan Habib’s <a href="https://www.youtube.com/watch?v=Wcc14aoylME&ref=daveabrock.com">nice video on the topic</a>, which helped me think through some scenarios.)</p><h2 id="our-use-case">Our use case</h2><p>For a quick use case, I’m using a silly loan application. I want to gather details about where someone lives now (to determine how much they pay and whatnot). The drop-down has five possible values, and I’ve got some custom components in my <code>Shared</code> directory that render based on what a user selects.</p><ul><li>Default state: <a href="https://github.com/daveabrock/DynamicComponentDemo/blob/master/Shared/DefaultDropdownComponent.razor?ref=daveabrock.com">DefaultDropdownComponent.razor</a></li><li>Rent: <a href="https://github.com/daveabrock/DynamicComponentDemo/blob/master/Shared/RentComponent.razor?ref=daveabrock.com">RentComponent.razor</a></li><li>Own house: <a href="https://github.com/daveabrock/DynamicComponentDemo/blob/master/Shared/OwnHouseComponent.razor?ref=daveabrock.com">OwnHouseComponent.razor</a></li><li>Own condo or townhouse: <a href="https://github.com/daveabrock/DynamicComponentDemo/blob/master/Shared/OwnCondoComponent.razor?ref=daveabrock.com">OwnCondoComponent.razor</a></li><li>I’m Dave’s roommate (fall-through condition): <a href="https://github.com/daveabrock/DynamicComponentDemo/blob/master/Shared/DaveRoommate.razor?ref=daveabrock.com">DaveRoommate.razor</a></li></ul><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/loanapp.jpg" class="kg-image" alt loading="lazy" width="935" height="547" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/loanapp.jpg 600w, https://www.daveabrock.com/content/images/2021/05/loanapp.jpg 935w" sizes="(min-width: 720px) 720px"></figure><h2 id="generate-drop-down">Generate drop-down</h2><p>To generate my drop-down list, I’ll use my component name as the <code>option value</code>. Here, I can use <a href="https://docs.microsoft.com/dotnet/csharp/language-reference/operators/nameof?ref=daveabrock.com">the <code>nameof</code> keyword</a>, which returns component names as constant strings.</p><p>Here’s the markup of <code>Index.cshtml</code> so far:</p><pre><code class="language-html">@page "/"

&lt;h1&gt;Loan application&lt;/h1&gt;

&lt;div class="col-4"&gt;
    What is your current living situation?
    &lt;select class="form-control"&gt;
        &lt;option value="@nameof(DefaultDropdownComponent)"&gt;Select a value&lt;/option&gt;
        &lt;option value="@nameof(RentComponent)"&gt;Rent&lt;/option&gt;
        &lt;option value="@nameof(OwnHouseComponent)"&gt;Own house&lt;/option&gt;
        &lt;option value="@nameof(OwnCondoComponent)"&gt;Own condo or townhouse&lt;/option&gt;
        &lt;option value="@nameof(DaveRoommate)"&gt;I'm Dave's roommate&lt;/option&gt;
    &lt;/select&gt;
&lt;/div&gt;
</code></pre><h2 id="write-change-event">Write change event</h2><p>We now need to decide what to do when a drop-down value is selected. To get the drop-down value, we work with <a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.components.changeeventargs?view=aspnetcore-5.0&ref=daveabrock.com">the <code>ChangeEventArgs</code> type</a> to get the value of the raised event—in this case, it’s the changed drop-down selection.</p><p>Before <code>DynamicComponent</code> came along, this is where you’d have logic to determine which component to render. Maybe you’d have a boolean flag, then use that in Razor markup. Instead, use <code>Type.GetType</code> to get the specific component to render.</p><pre><code class="language-csharp">Type selectedType = typeof(DefaultDropdownComponent);

public void OnDropdownChange(ChangeEventArgs myArgs)
{
  selectedType = Type.GetType($"DynamicComponentDemo.Shared.{myArgs.Value}");
}
</code></pre><p>Once I’m done with that, I can bind the drop-down’s <code>onchange</code> event to my <code>OnDropdownChange</code> method. Whenever the drop-down value changes, the method will trigger and determine which type it needs.</p><pre><code class="language-html">&lt;select @onchange="OnDropdownChange" class="form-control"&gt;
  &lt;option value="@nameof(DefaultDropdownComponent)"&gt;Select a value&lt;/option&gt;
  &lt;option value="@nameof(RentComponent)"&gt;Rent&lt;/option&gt;
  &lt;option value="@nameof(OwnHouseComponent)"&gt;Own house&lt;/option&gt;
  &lt;option value="@nameof(OwnCondoComponent)"&gt;Own condo or townhouse&lt;/option&gt;
  &lt;option value="@nameof(DaveRoommate)"&gt;I'm Dave's roommate&lt;/option&gt;
&lt;/select&gt;
</code></pre><p>Finally, I can render my <code>DynamicComponent</code>. I’ll place it right under my drop-down list.</p><pre><code>&lt;DynamicComponent Type="selectedType" /&gt;
</code></pre><p>Now we can see the page change using my <code>DynamicComponent</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/dynamic-component.gif" class="kg-image" alt loading="lazy" width="2008" height="1194"></figure><h2 id="optional-pass-in-parameters">Optional: Pass in parameters</h2><p>If your components have parameters, you can optionally pass them into your <code>DynamicComponent</code>. It takes a <code>Dictionary&lt;string, object&gt;</code>. The <code>string</code> is the name of your parameter, and the <code>object</code> is its value.</p><p>As a quick example, I can define <code>ComponentMetadata</code> through a quick class:</p><pre><code class="language-csharp">class ComponentMetadata
{
  public Type ComponentType { get; set; }
  public Dictionary&lt;string, object&gt; ComponentParameters { get; set; }
}
</code></pre><p>Then, I can create a dictionary for my components like this (only one component has a parameter):</p><pre><code class="language-csharp">private Dictionary&lt;string, ComponentMetadata&gt; paramsDictionaries = new()
{
  {
    "DefaultDropdownComponent",
    new ComponentMetadata { ComponentType = typeof(DefaultDropdownComponent)}
  },
  {
    "RentComponent",
    new ComponentMetadata { ComponentType = typeof(RentComponent)}
  },
  {
    "OwnCondoComponent",
     new ComponentMetadata { ComponentType = typeof(OwnCondoComponent)}
  },
  {
    "OwnHouseComponent",
    new ComponentMetadata { ComponentType = typeof(OwnCondoComponent)}
  },
  {
    "DaveRoommate",
    new ComponentMetadata
    {
      ComponentType = typeof(OwnCondoComponent),
      ComponentParameters = new Dictionary&lt;string, object&gt;()
      {
        { "CustomText", "Ooh, no." }
      }
    }
  }
};
</code></pre><p>Then, I could have logic that filters and passes in a <code>ComponentParameters</code> instance to the <code>DynamicComponent</code>, depending on what type I’m passing in. There’s a lot of power here—you could pass in data from an API or a database as well or even a function, as long as it returns a <code>Dictionary&lt;string, object&gt;</code>.</p><p>You might be asking: Why not use the catch-all approach?</p><pre><code class="language-html">&lt;DynamicComponent Type="@myType" MyParameter="Hello" MySecondParameter="Hello again" /&gt;.
</code></pre><p>According to Blazor architect Steve Sanderson, <a href="https://github.com/dotnet/aspnetcore/pull/28082?ref=daveabrock.com#issue-525829150">he says</a>:</p><blockquote>If we do catch-all parameters, then every explicit parameter on DynamicComponent itself - now and in the future - effectively becomes a reserved word that you can’t pass to a dynamic child. It would become a breaking change to add any new parameters to DynamicComponent as they would start shadowing child component parameters that happen to have the same name … It’s unlikely that the call site knows of some fixed set of parameter names to pass to all possible dynamic children. So it’s going to be far more common to want to pass a dictionary.</blockquote><h2 id="wrap-up">Wrap up</h2><p>In this post, we walked through the new <code>DynamicComponent</code>, which allows you to render components when you don’t know your types at runtime. We were able to render a component based on what a user selects from a drop-down list. We also explored how to pass in parameters to the <code>DynamicComponent</code> as well.</p><h2 id="references">References</h2><ul><li><a href="https://github.com/dotnet/aspnetcore/issues/26781?ref=daveabrock.com">Add DynamicComponent component</a> (GitHub issue)</li><li><a href="https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Components/Components/src/DynamicComponent.cs?ref=daveabrock.com">DynamicComponent source code</a> (GitHub)</li><li><a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-1/?ref=daveabrock.com#dynamiccomponent">ASP.NET Core updates in .NET 6 Preview 1</a> (Sourabh Shirhatti)</li><li><a href="https://www.youtube.com/watch?v=Wcc14aoylME&ref=daveabrock.com">Introduction to Dynamic Components in Blazor</a> (Hassan Habib)</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #43: 📅 DateTime might be seeing other people ]]></title>
        <description><![CDATA[ This week, we discuss new Date and Time APIs, and have a first look at hot reload. ]]></description>
        <link>https://www.daveabrock.com/2021/04/03/dotnet-stacks-43/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 02 Apr 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-3.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday! I hope you have a productive week and get more traction than an excavator on the Suez Canal. (Sorry.)</p><ul><li><strong>One big thing</strong>: New APIs for working with dates and times</li><li><strong>The little things</strong>: Hot reload, debugging config settings, Clean Architecture resources</li><li>Last week in the .NET world</li></ul><hr><h1 id="one-big-thing-new-apis-for-working-with-dates-and-times">One big thing: New APIs for working with dates and times</h1><p>If you’re walking on the street and a person asks you the time, you can look at your watch and tell them. It’s not so simple in .NET. If you only care about the time, you need to call and parse a <code>DateTime</code> or <code>DateTimeOffset</code> and scrap any date information. This approach can be incredibly error-prone, as these structs carry time-zone-related logic that isn’t written for getting the absolute date and time. (That doesn’t even include <a href="https://twitter.com/khellang/status/1374852735384834053?ref=daveabrock.com">its general weirdness</a>, like <code>DateTime.TimeOfDay</code> returning a <code>TimeSpan</code> and <code>DateTime.Date</code> returning a new <code>DateTime</code>. Even on its best days, the <code>DateTime</code> struct is both overloaded and confusing.)</p><p>Over <a href="https://github.com/dotnet/runtime/issues/49036?ref=daveabrock.com">on GitHub</a>, there’s a spicy issue (with some bikeshedding) discussing the possibility of a <code>Date</code> struct and a <code>Time</code> struct. Initially, Microsoft chose to expose the features as an external NuGet package. However, .NET developers are looking for the changes to be in the core of the .NET BCL APIs to avoid third-party library dependencies. The issue <a href="https://github.com/dotnet/runtime/issues/49036?ref=daveabrock.com#issue-820493809">has a proposed API</a>.</p><p>You may see these named differently as <a href="https://github.com/dotnet/runtime/issues/49036?ref=daveabrock.com#issuecomment-808582454">Visual Basic has used <code>Date</code></a> for three decades, and this would include a breaking change (and it might confuse folks using C# and VB). Right now, <code>DateOnly</code> seems to be the new name. I hope this is not a permanent name.</p><p>Here’s an interesting comment from the issue about a user’s scenario:</p><blockquote>I’m instead interested in the Date class most of all … We have a lot of products that is valid from date X to date Y. When we used DateTimeOffset we always had to remember to start at date X 00:00:00 and end at date Y 23:59:59.999. Then we switched to NodaTime and used LocalDate from there and all a sudden we could just compare dates without bother about time. We store Date in the database and map the column to a LocalDate now instead of a DateTimeOffset (which makes no sense since Date in the DB don’t have time or offset) which makes our lives even easier.</blockquote><p>This is all developers want from their SDKs: simplicity and predictability. The excellent <a href="https://nodatime.org/?ref=daveabrock.com">NodaTime library</a> provides these capabilities, but it isn’t coming from Microsoft—which stifles adoption. It’ll be great to have simpler APIs with working with dates <em>or</em> times, but it might be a while before we see it in the wild. (And for the record, <code>DateTime</code> isn’t going anywhere.)</p><hr><h1 id="the-little-things-hot-reload-debugging-config-settings-clean-architecture-resources">The little things: Hot reload, debugging config settings, Clean Architecture resources</h1><p>Say what you will about JavaScript (and believe me, <a href="https://daveabrock.com/2020/09/02/how-to-not-hate-javascript?ref=daveabrock.com">I have</a>), but it’s no mystery why it’s so widely used and adopted: the barrier of entry is low. I can open a text file, write some HTML markup (and maybe some JS), and open my web page to see the results. The instant feedback boosts productivity: in most common front-end frameworks, you can use “hot reload” functionality to see your changes immediately without having to restart the app.</p><p>That functionality is coming to ASP.NET Core (and Blazor) in .NET 6—we got a quick preview this week at Steve Sanderson’s <a href="https://youtu.be/5NqXBFn9v20?t=16050&ref=daveabrock.com">talk at NDC Manchester</a>. He showed off a promising prototype. Steve added and updated components (while preserving state), updated C# code, and worked well. The error handling looks nice, too—the app shows an error at the top of your page and will go away once you correct your issues and save. In some scenarios where you can’t do hot reload, your app will refresh your browser as it does now. This functionality is almost ready to show off to a larger audience—look for it in .NET 6 Preview 3, which will be released in the next few weeks.</p><p>He also showed off an <code>ErrorBoundary</code> component, allowing developers to have greater control over error handling in Blazor apps. As it is today, when unhandled exceptions occur, the user connection is dropped. With this new functionality, you can wrap an <code>ErrorBoundary</code> around specific markup, where unhandled exceptions in that section of code still allow users to access other parts of the app.</p><hr><p>A month ago, our friend <a href="https://twitter.com/cecilphillip/status/1362064796057755651?ref=daveabrock.com">Cecil Phillip tweeted</a>:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">IConfigurationRoot.GetDebugView is really useful for inspecting your resolved configuration settings! 👨🏽‍💻 It&#39;s been around since .NET Core 3.0 and I never knew! 👀<a href="https://t.co/iEKpDg4Rd3?ref=daveabrock.com">https://t.co/iEKpDg4Rd3</a><a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://twitter.com/hashtag/aspnetcore?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#aspnetcore</a> <a href="https://t.co/MxtFO9Btr5?ref=daveabrock.com">pic.twitter.com/MxtFO9Btr5</a></p>&mdash; Cecil L. Phillip 🇦🇬 (@cecilphillip) <a href="https://twitter.com/cecilphillip/status/1362064796057755651?ref_src=twsrc%5Etfw&ref=daveabrock.com">February 17, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>I never knew about this, either—it helps you discover your environmental variables and settings and where they’re getting read. (And, of course, it should be used for development purposes only so you don’t accidentally leak secrets.)</p><hr><p>When it comes to recommending architecture solutions, I use the two words that consultants live by: It Depends®. Even so, there’s a lot to like about the <a href="https://pusher.com/tutorials/clean-architecture-introduction?ref=daveabrock.com">Clean Architecture movement</a>.</p><p>This week, Patrick Smacchia <a href="https://blog.ndepend.com/clean-architecture-for-asp-net-core-solution/?ref=daveabrock.com">wrote about</a> Jason Taylor’s <a href="https://github.com/jasontaylordev/CleanArchitecture?ref=daveabrock.com">popular solution template</a>. Also, Mukesh Murugan has <a href="https://codewithmukesh.com/blog/blazor-hero-quick-start-guide/?ref=daveabrock.com">released <em>Blazor Hero</em></a>, a clean architecture template that includes common app scenarios under one umbrella. These are both good resources on understanding Clean Architecture.</p><hr><p>Lastly, <a href="https://twitter.com/dodyg/status/1374992298661003267?ref=daveabrock.com">this is exciting</a>:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">MapAction is a new way to create Web APIs without relying on Controller. (.NET 6 Preview 2)<a href="https://t.co/phsVF3UAgB?ref=daveabrock.com">https://t.co/phsVF3UAgB</a><a href="https://twitter.com/hashtag/aspnetcore?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#aspnetcore</a> <a href="https://t.co/Eveurkskk3?ref=daveabrock.com">pic.twitter.com/Eveurkskk3</a></p>&mdash; dodyg (@dodyg) <a href="https://twitter.com/dodyg/status/1374992298661003267?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 25, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><p>These links are new. I checked.</p><h2 id="-the-top-5">🔥 The Top 5</h2><ul><li>Andrew Lock <a href="https://andrewlock.net/debugging-configuration-values-in-aspnetcore/?ref=daveabrock.com">debugs configuration values in ASP.NET Core</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/getting-started-with-the-roslyn-apis-writing-code-with-code?ref=daveabrock.com">provides an introduction to the Roslyn APIs</a>.</li><li>Rachel Appel <a href="https://blog.jetbrains.com/dotnet/2021/03/24/work-with-asp-net-core-route-templates-in-resharper-and-rider/?ref=daveabrock.com">works with ASP.NET Core route templates in ReSharper and Rider</a>.</li><li>Ben Nadel <a href="https://www.bennadel.com/blog/4013-an-opinionated-guide-to-handling-pull-requests-prs-on-my-team.htm?ref=daveabrock.com">writes about how he handles PRs on his team</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/clean-architecture-for-asp-net-core-solution/?ref=daveabrock.com">writes about a case study on Clean Architecture</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/march-release-2021?ref=daveabrock.com">provides their March update</a>, and also <a href="https://devblogs.microsoft.com/azure-sdk/event-grid-ga?ref=daveabrock.com">announce the new Azure Event Grid client libraries</a>.</li><li>ReSharper 2021.1 <a href="https://blog.jetbrains.com/dotnet/2021/03/25/resharper-2021-1-beta/?ref=daveabrock.com">is in beta</a>, and so is <a href="https://blog.jetbrains.com/dotnet/2021/03/25/rider-2021-1-beta/?ref=daveabrock.com">Rider 2021.1</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Mar/23/LiveReloadServer-A-NET-Core-Based-Generic-Static-Web-Server-with-Live-Reload?ref=daveabrock.com">goes v1.0 with his LiveReloadServer</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Alberto Gimeno <a href="https://github.blog/2021-03-25-how-github-actions-renders-large-scale-logs/?ref=daveabrock.com">describes how GitHub Actions renders large-scale logs</a>.</li><li>Check out <a href="https://github.com/TessFerrandez/BuggyBits?ref=daveabrock.com">Tess Ferrandez’s repo with some nice debugging labs</a>.</li><li>For community standups: ASP.NET <a href="https://www.youtube.com/watch?v=UnbJrC0WN1U&ref=daveabrock.com">talks about Balea authorization</a> and Entity Framework <a href="https://www.youtube.com/watch?v=3-Izu_qLDqY&ref=daveabrock.com">talks about what’s new in EF Core Power Tools</a>.</li><li>Zack Koppert <a href="https://github.blog/2021-03-23-solving-the-innersource-discovery-problem/?ref=daveabrock.com">writes about solving innersource discovery problems at GitHub</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=9oroj2TmxBs&ref=daveabrock.com">talks to Steve Smith about API endpoints</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/blazor/2021/03/24/Blazor-Excluding-Files-from-PWA-Asset-Cache.html?ref=daveabrock.com">excludes files from the PWA asset cache in Blazor</a>.</li><li>Kevin Dockx <a href="https://www.pluralsight.com/blog/software-development/odata-asp-net-core?ref=daveabrock.com">works with OData in ASP.NET Core</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/tetris-in-blazor-webassembly/?ref=daveabrock.com">writes a Tetris game in Blazor WebAssembly</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/03/23/setting-dynamic-metadata-for-blazor-web-assembly/?ref=daveabrock.com">sets dynamic metadata for Blazor Web Assembly</a>.</li><li>Jeetendra Gund <a href="https://www.telerik.com/blogs/how-to-get-httpcontext-asp-net-core?ref=daveabrock.com">gets HttpContext in ASP.NET Core</a>.</li><li>The Code Maze blog <a href="https://code-maze.com/creating-resilient-microservices-in-net-with-polly/?ref=daveabrock.com">creates resilient microservices in .NET with Polly </a>.</li><li>Daniel Gomez Jaramillo <a href="https://www.c-sharpcorner.com/article/building-an-event-information-portal-with-asp-net-5/?ref=daveabrock.com">builds an event information portal with ASP.NET Core 5</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/03/20/blazor-api-handling/?ref=daveabrock.com">handles APIs in Blazor</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/how-to-build-a-basic-http-api-with-aspnet-core?ref=daveabrock.com">builds a basic HTTP API in ASP.NET Core</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-null-models-in-post-requests?ref=daveabrock.com">warns about null models in POST requests in ASP.NET Core</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Kunal Pathak <a href="https://devblogs.microsoft.com/dotnet/loop-alignment-in-net-6?ref=daveabrock.com">writes about loop alignment in .NET 6</a>.</li><li>Niels Swimberghe says: <a href="https://swimburger.net/blog/dotnet/don-t-use-httpcontext-current-especially-when-using-async?ref=daveabrock.com">don’t use <code>HttpContext.Current</code>, especially when using async</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/winui-yes-another-desktop-framework-but-cooler-than-you-might-think?ref=daveabrock.com">writes about WinUI</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/03/25/desktop-options.aspx?ref=daveabrock.com">writes about Microsoft’s desktop dev options</a>.</li><li>Alex Klaus <a href="https://alex-klaus.com/hosting-spa-in-dotnet/?ref=daveabrock.com">works with caching and environment variables</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Paul Michaels <a href="https://www.pmichaels.net/2021/03/20/service-bus-management-and-auto-forwarding/?ref=daveabrock.com">works on Service Bus management and auto-forwarding</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/03/24/azure-functions-net5.aspx?ref=daveabrock.com">writes about what’s next for Azure Functions</a>.</li><li>Johnny Reilly <a href="https://blog.johnnyreilly.com/2021/03/20/bicep-meet-azure-pipelines/?ref=daveabrock.com">works with Bicep and Azure Pipelines</a>.</li><li>Joseph Guadagno creates a search suggestion widget <a href="https://www.josephguadagno.net/2021/03/27/creating-a-search-suggestion-widget-using-azur-maps-search-service-and-kendoui-autocomplete.?ref=daveabrock.com">using Azure Maps Search Service and KendoUI</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Jiří Činčura <a href="https://www.tabsoverspaces.com/233855-fusing-await-using-and-await-foreach-and-await?ref=daveabrock.com">fuses await using and await foreach and await</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Asynchronous-Streams?ref=daveabrock.com">writes about async streams</a>.</li><li>Thomas Levesque <a href="https://thomaslevesque.com/2021/03/19/csharp-9-records-as-strongly-typed-ids-part-5-final-bits-and-conclusion/?ref=daveabrock.com">wraps up his series on C# 9 records as strongly-typed IDs</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/03/25/csharp-using-tuples-to-initialize-properties/?ref=daveabrock.com">uses tuples in C# to initialize properties in the constructor and to deconstruct objects</a>.</li><li>Daniel B. Markham <a href="https://danielbmarkham.com/outlines-of-a-supercompiler-in-f/?ref=daveabrock.com">blogs about the outlines of a supercompiler in F#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Mark Downie <a href="https://www.poppastring.com/blog/collecting-managed-crash-dumps-on-app-services-for-linux?ref=daveabrock.com">collects managed crash dumps on App Services for Linux</a>.</li><li>Laurent Kempé <a href="https://laurentkempe.com/2021/03/25/calling-dapr-service-with-grpc/?ref=daveabrock.com">calls a Dapr service with gRPC</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/easy-generation-of-fake-dummy-data-in-c-with-faker-net/?ref=daveabrock.com">works with fake/dummy data in C# with Faker</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/how-to-add-a-view-to-an-entity-framework-core-dbcontext?ref=daveabrock.com">adds a view to an EFCore DbContext</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/2021/03/19/Display-a-Docker-Build-Version.html?ref=daveabrock.com">displays a Docker build version</a>.</li><li>Harshal Limaye <a href="https://www.c-sharpcorner.com/article/20-git-commands-you-should-know/?ref=daveabrock.com">writes about 20 Git commands you should know</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>András Tóth <a href="https://www.banditoth.hu/2021/03/22/xamarin-forms-reopening-application-best-pratices/?ref=daveabrock.com">discuss best practices for reopening apps in Xamarin</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/animating-page-transitions-in-xamarin-forms/?ref=daveabrock.com">animates page transitions in Xamarin Forms</a>.</li><li>Leomaris Reyes <a href="https://www.syncfusion.com/blogs/post/replicating-banking-exploration-ui-in-xamarin.aspx?ref=daveabrock.com">replicates a banking exploration UI in Xamarin</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>The Software Alchemy blog <a href="https://blog.jacobsdata.com/2021/03/22/scaffold-your-clean-ddd-web-application-part-5-domain-driven-design-entity-mapping-strategies?ref=daveabrock.com">works on domain-driven design entity mapping strategies</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/is-a-rest-api-with-cqrs-possible/?ref=daveabrock.com">asks: is a REST API with CQRS possible</a>?</li><li>Ashley Davis <a href="https://thenewstack.io/scaling-microservices-on-kubernetes/?ref=daveabrock.com">scales microservices on Kubernetes</a>.</li><li>Priyanka <a href="https://www.syncfusion.com/blogs/post/linq-mocking-in-asp-net-core.aspx?ref=daveabrock.com">mocks with LINQ to unit test in ASP.NET Core</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1732&ref=daveabrock.com">talks to Mads Kristensen about Visual Studio feedback</a>.</li><li>The .NET Core Show discusses <a href="https://dotnetcore.show/episode-72-emulating-a-video-game-system-in-net-with-ryujinx/?ref=daveabrock.com">emulating a video game system in .NET with Ryujinx</a>.</li><li>The Azure DevOps Podcast talks to <a href="http://azuredevopspodcast.clear-measure.com/richard-campbell-on-the-history-of-net-episode-133?ref=daveabrock.com">Richard Campbell on the history of .NET</a>.</li><li>The Coding After Work podcast <a href="http://codingafterwork.com/2021/03/22/episode-57-react-writing-a-book-and-blazor-with-carl-rippon/?ref=daveabrock.com">talks to Carl Rippon about React, books, and Blazor</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-188-designing-for-scale-with-james-avery/?ref=daveabrock.com">talks to James Avery about designing for scale</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-061-C-9-deep-dive-with-jason-bock/?ref=daveabrock.com">talks to Jason Bock about C# 9</a>.</li><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-369-Learn-Azure-SQL?ref=daveabrock.com">talks about learning Azure SQL</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>The Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Choices-in-Desktop-Development?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">talks to Sam Basu about desktop development choices</a>.</li><li>At Technology and Friends, <a href="https://www.davidgiard.com/2021/03/22/JasonFarrellOnKubernetes.aspx?ref=daveabrock.com">David Giard talks to Jason Farrell about Kubernetes</a>.</li><li>Azure Friday discusses <a href="https://channel9.msdn.com/Shows/Azure-Friday/Best-practices-for-Azure-Container-Instances-ACI-with-GitHub-Actions?ref=daveabrock.com">best practices for Azure Container Instances (ACI) with GitHub Actions</a>.</li><li>The On .NET Show <a href="https://dev.to/dotnet/on-net-episode-c-source-generators-3fd8?ref=daveabrock.com">talks about C# source generators</a> and <a href="https://www.youtube.com/watch?v=PDdHa0ushJ0&ref=daveabrock.com">cloud native patterns</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use Azure Static Web Apps with Azure DevOps pipelines ]]></title>
        <description><![CDATA[ In this post, we discuss how to use Azure Static Web Apps from a pipeline in Azure DevOps. ]]></description>
        <link>https://www.daveabrock.com/2021/04/01/static-web-apps-azure-pipelines/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe9a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 31 Mar 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1517060826726-eb8ff5938eb8?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIxfHxwaXBlc3xlbnwwfHx8fDE2MTk4Mjg0NzA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Last year, Microsoft released <a href="https://azure.microsoft.com/services/app-service/static/?ref=daveabrock.com">Azure Static Web Apps</a>, a great way to bundle your static app with a serverless Azure Functions backend. If you have a GitHub repository, Azure Static Web Apps has you covered. You create an instance in Azure, select a GitHub repository, and Azure creates a GitHub Actions CI/CD pipeline for you that’ll automatically trigger when you merge a pull request into your <code>main</code> branch. It’s still in preview, but a GA release isn’t too far off.</p><p>To borrow <a href="https://www.goodreads.com/quotes/23494-any-customer-can-have-a-car-painted-any-colour-that?ref=daveabrock.com">from a famous Henry Ford quote</a>: <em>you can have it from any repo you want, so long as it’s GitHub</em>.</p><p>That has changed. Azure Static Web Apps now provides Azure DevOps support. If you have a repository in Azure DevOps, you can wire up an Azure Pipelines YAML file that builds and deploys your app to Azure Static Web Apps. While it isn’t as streamlined and elegant as the GitHub experience—you need to configure your deployment token manually, and you don’t get automatic staging environments—it sure beats the alternative for Azure DevOps customers (that is, no Azure Static Web Apps support at all).</p><p>Since last fall, I’ve been experimenting with Azure Static Web Apps for my <em>Blast Off with Blazor</em> <a href="https://daveabrock.com/tag/blast-off-blazor?ref=daveabrock.com">blog posts</a> and <a href="https://github.com/daveabrock/NASAImageOfDay?ref=daveabrock.com">accompanying repository</a>. In this post, I’ll deploy my repository’s code from Azure DevOps to try out the support.</p><h2 id="prerequisites">Prerequisites</h2><p>Before we begin, I’ll assume you have an active Azure DevOps project. If you don’t, <a href="https://docs.microsoft.com/en-us/azure/devops/organizations/projects/create-project?view=azure-devops-2020&tabs=preview-page&ref=daveabrock.com">check out the docs</a>.</p><p>If you need to import a Git repository from your local machine, as I did, perform the following steps:</p><ol><li>Navigate to your Azure DevOps repository.</li><li>Select <strong>Import</strong>.</li><li>Enter the URL of your Git repository.</li><li>Select <strong>Import</strong> again.</li></ol><h2 id="create-an-azure-static-web-apps-resource">Create an Azure Static Web Apps resource</h2><p>To get started, create a new Azure Static Web App resource from the Azure Portal.</p><ol><li>Navigate to the Azure Portal at <em><a href="https://portal.azure.com/?ref=daveabrock.com">portal.azure.com</a></em>.</li><li>From the global search box at the top, search for and select <strong>Azure Static Web Apps (Preview)</strong>.</li><li>Select <strong>Create</strong>.</li><li>Enter details for your subscription, resource group, name, and region.  Under <em>Deployment details</em>, click <strong>Other</strong>. This option bypasses the automated GitHub flow and tells Azure you don’t need it.</li></ol><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/create-static-app-resource.jpg" class="kg-image" alt loading="lazy" width="2000" height="1663" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/create-static-app-resource.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/create-static-app-resource.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/create-static-app-resource.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/create-static-app-resource.jpg 2092w" sizes="(min-width: 720px) 720px"></figure><p>Once you’re done, click <strong>Review + Create</strong>, then <strong>Create</strong>. When the deployment completes, navigate to your new resource. You’ll now need to grab the deployment token to use with Azure DevOps.</p><h2 id="access-deployment-token">Access deployment token</h2><p>Since you clicked <strong>Other</strong> when you created your resource, you’ll need to do some manual work to get Azure Static Web Apps working with Azure DevOps. To do so, select <strong>Manage deployment token</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/manage-deployment-token-option.jpg" class="kg-image" alt loading="lazy" width="2000" height="842" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/manage-deployment-token-option.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/manage-deployment-token-option.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/manage-deployment-token-option.jpg 1600w, https://www.daveabrock.com/content/images/size/w2400/2021/05/manage-deployment-token-option.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>From there, copy your token to a text editor so you can use it later. (Or, if you’re fancy, you can use your operating system’s <a href="https://www.onmsft.com/how-to/how-to-turn-on-clipboard-history-on-windows-10-to-save-time?ref=daveabrock.com">clipboard history features</a>.)</p><h2 id="create-azure-pipelines-task">Create Azure Pipelines task</h2><p>Now, we’ll need to create an Azure Pipelines task in Azure DevOps.</p><p>From your Azure DevOps repository, select <strong>Set up build</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/set-build-button.jpg" class="kg-image" alt loading="lazy" width="2000" height="635" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/set-build-button.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/set-build-button.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/set-build-button.jpg 1600w, https://www.daveabrock.com/content/images/size/w2400/2021/05/set-build-button.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>From <em>Configure your pipeline</em>, select <strong>Starter pipeline</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/starter-pipeline.jpg" class="kg-image" alt loading="lazy" width="1875" height="1542" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/starter-pipeline.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/starter-pipeline.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/starter-pipeline.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/starter-pipeline.jpg 1875w" sizes="(min-width: 720px) 720px"></figure><p>In your pipeline, replace the existing YAML content with a new <code>AzureStaticWebApp</code> task. Pay special attention to the <code>inputs</code> section:</p><ul><li>The <code>app_location</code> specifies the root of your application code. For me, this sits in a Blazor client directory at <code>Blazor.Client</code>.</li><li>The <code>api_location</code> is the location of your Azure Functions code. <strong>Pay attention here!</strong> If no API is found in the specified location, the build assumes it doesn’t exist and silently fails. (Trust me … I know this personally.)</li><li>The <code>output_location</code> includes the build output directory relative to <code>app_location</code>. For me, my static files reside in <code>wwwroot</code>.</li></ul><p>We’ll work on the <code>azure_static_web_app_api_token</code> value soon.</p><p>Here’s my YAML file. (You’ll notice it’s a bit cleaner than the <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/.github/workflows/azure-static-web-apps-jolly-ground-0bdb93d10.yml?ref=daveabrock.com">GitHub Action</a>.)</p><pre><code class="language-yaml">trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: AzureStaticWebApp@0
    inputs:
      app_location: "BlastOff.Client"
      api_location: "BlastOff.Api"
      output_location: "wwwroot"
    env:
      azure_static_web_apps_api_token: $(deployment_token)
</code></pre><p>Before we kick off the pipeline, we need to add our Azure Static Web Apps deployment token as an Azure Pipelines variable. To do so, select <strong>Variables</strong> and create a variable called <strong>deployment_token</strong> (assuming that’s what you named the value of <code>azure_static_web_apps_api_token</code>). Finally, select <strong>Keep this value secret</strong>, then click <strong>OK</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/new-variable.jpg" class="kg-image" alt loading="lazy" width="1155" height="1700" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/new-variable.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/new-variable.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/new-variable.jpg 1155w" sizes="(min-width: 720px) 720px"></figure><p>Select <strong>Save</strong>, then <strong>Save and run</strong>. With a little luck, it might pass on the first try. Congratulations! You now have an Azure Static Web Apps site built from an Azure DevOps repository.</p><h2 id="side-note-the-minimal-azure-pipelines-yaml-file">Side note: The minimal Azure Pipelines YAML file</h2><p>I can’t help but notice the brevity of the Azure Pipelines YAML file. Here’s another look at the file:</p><pre><code class="language-yaml">trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: AzureStaticWebApp@0
    inputs:
      app_location: "BlastOff.Client"
      api_location: "BlastOff.Api"
      output_location: "wwwroot"
    env:
      azure_static_web_apps_api_token: $(deployment_token)
</code></pre><p>Compare that to the look of the GitHub Actions YAML file that Azure Static Web Apps created for me:</p><pre><code class="language-yaml">name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' &amp;&amp; github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v0.0.1-preview
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_BLACK_DESERT_00CF9D310 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} 
          action: "upload"
          app_location: "BlastOff.Client"
          api_location: "BlastOff.Api"
          output_location: "wwwroot"

  close_pull_request_job:
    if: github.event_name == 'pull_request' &amp;&amp; github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    steps:
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@v0.0.1-preview
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_BLACK_DESERT_00CF9D310 }}
          action: "close"
</code></pre><p>While the deploy step is similar between the two, the GitHub Actions file has a lot of noise related to managing pull requests. As such, a common question might be: <em>Do I need to add PR trigger steps in my Azure Pipelines file?</em> No! In my testing, I successfully merged a pull request to <code>main</code> and kick off a successful build and deploy without updating the YAML file manually.</p><h2 id="should-i-use-azure-static-web-apps-with-azure-devops-or-github">Should I use Azure Static Web Apps with Azure DevOps or GitHub?</h2><p>With two ways to deploy your Azure Static Web Apps (with the possibility of more), you might be wondering which option to choose.</p><p>Microsoft will not be supporting competing code management/DevOps solutions long-term. Azure DevOps isn’t being phased out anytime soon, but the long-term investment will be in GitHub. If you are building new and don’t have a dependency on Azure DevOps, Azure Static Web Apps with GitHub is the way to go. However, if you are using Azure DevOps—for many, the robust enterprise capabilities of Azure DevOps make it hard to leave until GitHub matures in that space—it’s a nice solution.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we demonstrated how to deploy an Azure Static Web App using an Azure DevOps pipeline. We created an Azure Static Web Apps resource, retrieved a deployment token, created an Azure Pipelines task, and explored why you would want to use GitHub or Azure DevOps for your Azure Static Web Apps.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #42: 🔌 When Active Directory isn&#x27;t so active ]]></title>
        <description><![CDATA[ This week, we discuss the Azure AD outage and also talk about a variety of other topics. ]]></description>
        <link>https://www.daveabrock.com/2021/03/27/dotnet-stacks-42/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe99</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 26 Mar 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-4.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday to you all. Here’s what we have on tap this week.</p><ul><li><strong>One big thing</strong>: When Active Directory isn’t so active</li><li><strong>The little things</strong>: A bunch of odds and ends</li><li>Last week in the .NET world</li></ul><h1 id="one-big-thing-when-active-directory-isn-t-so-active">One big thing: When Active Directory isn’t so active</h1><p>Mondays are typically long days. Tell that to Microsoft, who last Monday suffered <a href="https://status.azure.com/status/history/?ref=daveabrock.com">another Azure Active Directory outage</a> that took down most apps consuming AD, including the Azure Portal, Teams, Exchange, Azure Key Vault, Azure Storage, and more. The outage lasted a few hours (2 pm until 7 pm, in these parts), but lingering effects lasted much longer. The timing was unfortunate—isn’t it always?—as they’re rolling out <a href="https://redmondmag.com/articles/2021/01/05/microsoft-upping-azure-ad-sla.aspx?ref=daveabrock.com">99.99% availability in April</a> to customers with Premium licenses.</p><p>What happened? Azure AD runs an automated system that removes keys no longer in use. To support a “complex cross-cloud migration,” a specific key was marked to retain for longer than usual. Due to a bug, the system ignored the flag, the key was removed, and Azure AD stopped trusting the tokens from the removed key. When you pair this with the outage <a href="https://build5nines.com/azure-ad-is-down-blocking-access-to-azure-teams-and-more-september-28-2020-microsoft-azure-outage?ref=daveabrock.com">from September 2020</a>—the culprit there was a code defect—you have a right to be concerned about Azure AD if you aren’t already.</p><p>Meanwhile, updates were quicker on Twitter than on their status pages. Microsoft has owned up to this, saying: <em>“We identified some differences in detail and timing across Azure, Microsoft 365 and Dynamics 365 which caused confusion for customers … We have a repair item to provide greater consistency and transparency across our services.”</em></p><p>For Microsoft’s part, the notice says they are engaged in a two-stage process to improve Azure AD, including an effort to avoid what happened last Monday. This effort includes instituting a backend Safe Deployment Process (SDP) system to prevent these types of problems. The first stage is complete, and the second stage is planned for completion later this year.</p><p>Let’s hope so. It’s hard to swallow that such a critical service has a single point of failure. While there are many reasons for <em>and</em> against this design, we can all agree that Microsoft needs to improve resiliency for Azure AD. Instead of the time-honored tradition of Azure executives at Build or Ignite showing off a global map of all their new regions, I think we’d much rather have a slide showing off improvements to their flagship identity service.</p><h1 id="the-little-things-a-bunch-of-odds-and-ends">The little things: A bunch of odds and ends</h1><p>In the <a href="https://www.youtube.com/watch?v=DkElWa3&ref=daveabrock.com">ASP.NET standup this week</a>, James Newton-King joined Jon Galloway to talk about <a href="https://devblogs.microsoft.com/aspnet/grpc-performance-improvements-in-net-5/?ref=daveabrock.com">gRPC improvements for .NET 5</a>. It gets low-level at times, but I enjoyed it and learned a lot.</p><p>For the improvements, benchmarks show the .NET gRPC implementation just behind Rust (which isn’t a framework, so that’s saying something). Server performance is 60% faster than .NET Core 3.1, and client performance is 230% faster.</p><p>To answer your next question: since IIS and HTTP.sys now support gRPC, does Azure App Service support it too? Not yet, but <a href="https://github.com/dotnet/aspnetcore/issues/9020?ref=daveabrock.com">keep an eye on this issue</a> for the latest updates.</p><hr><p>Adam Sitnik, an engineer on the .NET team and the person behind BenchmarkDotNet, has <a href="https://github.com/adamsitnik/awesome-dot-net-performance?ref=daveabrock.com">a new repository</a> full of valuable resources for learning about .NET performance.</p><hr><p>Steve Sanderson, the creator of Blazor (and a <a href="https://daveabrock.com/2021/01/17/dev-discussions-steve-sanderson?ref=daveabrock.com">recent interview subject</a>), has <a href="https://github.com/dotnet/aspnetcore/issues/30940?ref=daveabrock.com">created an excruciatingly detailed Blazor issue in GitHub</a> to catch and handle exceptions thrown within a particular UI subtree. This capability accomplishes an idea of “<a href="https://github.com/dotnet/aspnetcore/issues/13452?ref=daveabrock.com">global exception handling</a>” in Blazor.</p><hr><p>This week, Nick Craver noted why Stack Overflow likely isn’t migrating to .NET 5. (You’ll want to read <a href="https://twitter.com/Nick_Craver/status/1371800961002405888?ref=daveabrock.com">the entire thread</a> for context.)</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I got several pings about .NET 5 for Stack Overflow over break: unfortunately, no good news there.<br><br>We&#39;ve hit many flaky build failures with the .NET 5 SDK even when building 3.1, so many that we&#39;ve reverted back to the 3.1 SDK and have no timeline on a 5.x rollout.</p>&mdash; Nick Craver (@Nick_Craver) <a href="https://twitter.com/Nick_Craver/status/1371800961002405888?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 16, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><p>Shay Rojansky <a href="https://twitter.com/shayrojansky/status/1372669765995655170?ref=daveabrock.com">notes that EF Core</a> is now fully annotated for C# reference nullability. As a whole, fully annotating nullability across .NET should be complete in .NET 6.</p><hr><p>I’ve been intrigued this week by Daniel Terhorst-North writing about why he feels “<a href="https://dannorth.net/2021/03/16/cupid-the-back-story/?ref=daveabrock.com">every single element of SOLID is wrong</a>.” It’s quite the statement, but the more you read, the less revolutionary it sounds. Things change and evolve. Whether it’s SOLID or any other prescribed “best practice,” I’ve learned to take things with a grain of salt and consider the tradeoffs.</p><hr><p>I’ve been working with many scheduled GitHub Actions to automate much of how I put together this newsletter every week (like adding links to a persistent store and generating my Markdown file). With scheduling tasks, as in timed Azure Functions triggers, CRON is still king. It’s nice that GitHub Actions translates CRON syntax for you on hover, but I’m still going to mess it up.</p><p>What saves me every time is the <em><a href="https://crontab.guru/?ref=daveabrock.com">crontab.guru</a></em> site. (I’m not being asked to say this. I’m just a fan.) You can edit a CRON expression and easily see how it looks for a CRON amateur. You can also hit quick links with examples ready to go, like <em><a href="https://crontab.guru/every-day-8am?ref=daveabrock.com">crontab.guru/every-day-8am</a></em>.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/crontab.jpg" class="kg-image" alt="crontab.guru" loading="lazy" width="2000" height="1256" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/crontab.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/crontab.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/crontab.jpg 1600w, https://www.daveabrock.com/content/images/size/w2400/2021/05/crontab.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-4">🔥 The Top 4</h2><ul><li>Thomas Ardal <a href="https://blog.elmah.io/avoid-password-reuse-with-pwned-passwords-and-asp-net-core/?ref=daveabrock.com">avoids password reuse with Pwned Passwords and ASP.NET Core</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/03/the-case-of-the-last-t/?ref=daveabrock.com">writes how the Azure SDK team decided to capitalize the T in Azure.IoT</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/running-kubernetes-and-the-dashboard-with-docker-desktop/?ref=daveabrock.com">runs Kubernetes and the dashboard with Docker Desktop</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/create-zip-files-on-http-request-without-intermediate-files-using-aspdotnet-mvc-razor-pages-and-endpoints?ref=daveabrock.com">creates ZIP files on HTTP request without intermediate files using ASP.NET MVC, Razor Pages, and endpoints</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Sourabh Shirhatti writes <a href="https://devblogs.microsoft.com/dotnet/opentelemetry-net-reaches-v1-0?ref=daveabrock.com">how OpenTelemetry has reached v1.0</a>.</li><li>Michael A. Hawker <a href="https://blogs.windows.com/windowsdeveloper/2021/03/16/announcing-windows-community-toolkit-v7-0?ref=daveabrock.com">announces Windows Community Toolkit v7.0</a>.</li><li>Bri Achtman <a href="https://devblogs.microsoft.com/dotnet/ml-net-and-model-builder-march-updates?ref=daveabrock.com">provides ML.NET and Model Builder March updates</a>.</li><li>Norm Johanson and Philip Pittle <a href="https://aws.amazon.com/blogs/developer/reimagining-the-aws-net-deployment-experience/?ref=daveabrock.com">writes about the new deployment experience for AWS on .NET</a>.</li><li>Jon Douglas <a href="https://devblogs.microsoft.com/nuget/performance-and-polish-with-nuget-5-9?ref=daveabrock.com">writes about the NuGet 5.9 release</a>.</li><li>Antonin Prochazka <a href="https://blog.postsharp.net/post/postsharp-6-9-rc-visual-studio-tooling-performance-improvements.html?ref=daveabrock.com">announces PostSharp 6.9 RC</a>.</li><li>JetBrains releases <a href="https://blog.jetbrains.com/dotnet/2021/03/17/rider-resharper-2020-3-4/?ref=daveabrock.com">Rider 2020.3.4 and ReSharper 2020.3.4</a>, and also brings <a href="https://blog.jetbrains.com/dotnet/2021/03/18/scaffolding-for-asp-net-core-projects-comes-to-rider-2021-1/?ref=daveabrock.com">scaffolding for ASP.NET Core projects Rider 2021.1</a>.</li><li>Visual Studio 2019 v16.9.2 <a href="https://docs.microsoft.com/visualstudio/releases/2019/release-notes?ref=daveabrock.com#16.9.2">is now available</a>.</li><li>Taylor Blau <a href="https://github.blog/2021-03-15-highlights-from-git-2-31/?ref=daveabrock.com">recaps Git 2.31</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>For community standups: Machine Learning <a href="https://www.youtube.com/watch?v=Nj3z6d-SJWs&ref=daveabrock.com">talks about extending ML.NET</a> and ASP.NET <a href="https://www.youtube.com/watch?v=DkElWa3--8s&ref=daveabrock.com">talks to James Newton-King about recent gRPC performance improvements</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/windows-dev-platform/?ref=daveabrock.com">writes about a vision for the Windows developer platform</a> and also <a href="https://nicksnettravels.builttoroam.com/stop-talking-about-uwp/?ref=daveabrock.com">wants to stop talking about UWP</a>.</li><li>David Ramel writes how the <a href="https://visualstudiomagazine.com/articles/2021/03/16/wct-7.aspx?ref=daveabrock.com">Windows Community Toolkit is getting the .NET Standard MVVM Library</a>, and also <a href="https://visualstudiomagazine.com/articles/2021/03/16/ef-core.aspx?ref=daveabrock.com">writes about the slow EF Core adoption</a>.</li><li>Dirkjan Bussink <a href="https://github.blog/2021-03-18-how-we-found-and-fixed-a-rare-race-condition-in-our-session-handling/?ref=daveabrock.com">writes about how GitHub found and fixed a rare race condition in its session handling</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=UkFBwMOT5Ag&ref=daveabrock.com">talks to Vahid Farahmandian about the Middle East’s largest maritime ERP</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Dave Brock <a href="https://daveabrock.com/2021/03/17/blast-off-blazor-add-dialog?ref=daveabrock.com">adds a shared dialog component in Blazor</a>.</li><li>Josef Ottosson <a href="https://josef.codes/select-action-method-based-on-header-value-asp-net-core/?ref=daveabrock.com">selects an action method based on header values in ASP.NET Core</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/how-to-read-the-appsettings-json-configuration-file-in-asp-net-core?ref=daveabrock.com">writes about how to read the appsettings.json Configuration File in ASP.NET Core</a>.</li><li>Scott Brady <a href="https://www.scottbrady91.com/ASPNET-Identity/ASPNET-Identity-Password-Policies-with-Password-Managers?ref=daveabrock.com">integrates ASP.NET identity password policies with password managers</a>.</li><li>Ian Russell <a href="https://www.softwarepark.cc/blog/2021/3/12/introduction-to-web-programming-in-f-with-giraffe-part-2?ref=daveabrock.com">works with F# and Giraffe</a>.</li><li>Muhammed Saleem <a href="https://code-maze.com/azure-sql-with-asp-net-core-web-api/?ref=daveabrock.com">uses Azure SQL with an ASP.NET Core Web API</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/resolve-services-in-aspnet-core-startup?ref=daveabrock.com">resolves services in ASP.NET Core</a>.</li><li>Isaac Levin writes about migrating the <a href="https://devblogs.microsoft.com/dotnet/the-path-to-net-5-and-blazor-webassembly-with-some-fun-sprinkled-in?ref=daveabrock.com">Rock, Paper, Scissors, Lizard, Spock (RPSLS) site to .NET 5 and Blazor Web Assembly</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-03-15-graphql-on-azure-part-6-subscriptions-with-signalr/?ref=daveabrock.com">continues his series on GraphQL on Azure with some SignalR</a>.</li><li>Mark Heath <a href="https://markheath.net/post/user-delegation-sas?ref=daveabrock.com">generates an Azure Blob Storage User Delegation SAS</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Matthew MacDonald <a href="https://medium.com/young-coder/c-10-3-candidate-features-that-could-make-the-final-cut-3b46f4a62284?ref=daveabrock.com">writes about three possible C# 10 features</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/03/14/upload-files-to-github-repository?ref=daveabrock.com">uses C# to upload files to a GitHub repository</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/create-a-zip-file-with-dotnet-5?ref=daveabrock.com">creates a Zip file with .NET 5</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Laurent Kempé <a href="https://laurentkempe.com/2021/03/16/service-to-service-invocation-with-dapr-dotnet-sdk/?ref=daveabrock.com">works on service-to-service invocation with the Dapr SDK</a>.</li><li>Donovan Brown <a href="https://www.donovanbrown.com/post/Develop-Dapr-Components-in-a-container?ref=daveabrock.com">develops Dapr components in a container</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/ryujinx-is-an-experimental-nintendo-switch-emulator-written-in-c-for-net-core?ref=daveabrock.com">writes about Ryujinx, an experimental Nintendo Switch emulator written in C# for .NET Core</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/03/15/generate-dockerfile-for-net-applications-with-rider/?ref=daveabrock.com">generates Dockerfiles for .NET applications with Rider</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/03/12/uno-winui.aspx?ref=daveabrock.com">writes about WinUI teaming up with Uno for cross-platform apps</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Brad Dean <a href="https://truegeek.com/2021/03/16/i-updated-forms-to-maui/?ref=daveabrock.com">updates a Xamarin.Forms project to MAUI</a>.</li><li>Jesse Liberty <a href="http://jesseliberty.com/2021/03/17/xamarin-best-practices/?ref=daveabrock.com">writes about Xamarin best practices</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/getting-started-with-local-notifications-xamarin-forms?ref=daveabrock.com">works with local notifications in Xamarin.Forms</a>.</li><li>James Montemagno <a href="https://devblogs.microsoft.com/xamarin/great-looking-settings-screens-for-xamarin-forms?ref=daveabrock.com">builds settings screens for Xamarin.Forms</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Steve Smith <a href="https://ardalis.com/hardware-hides-many-sins/?ref=daveabrock.com">writes about how hardware hides many sins</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/decomposing-crud-to-a-task-based-ui/?ref=daveabrock.com">decomposes CRUD to a task-based UI</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/investigating-a-linux-cve-with-net-images?ref=daveabrock.com">investigates a Linux CVE with .NET images</a>.</li><li>Daniel Terhorst-North <a href="https://dannorth.net/2021/03/16/cupid-the-back-story/?ref=daveabrock.com">writes about his distaste for SOLID</a>.</li><li>Ian Miell asks: <a href="https://zwischenzugs.com/2021/03/15/when-should-i-interrupt-someone/?ref=daveabrock.com">when should I interrupt someone</a>?</li><li>Jason Farrell <a href="https://jfarrell.net/2021/03/14/common-misconception-1-entity-framework-needs-a-data-layer/?ref=daveabrock.com">addresses the misconception that Entity Framework needs a data layer</a>.</li><li>Jon Hilton <a href="https://www.telerik.com/blogs/building-design-system-friendly-components?ref=daveabrock.com">builds design system–friendly components</a>.</li><li>Subodh Sohoni <a href="https://www.dotnetcurry.com/microsoft-azure/microservices-architecture?ref=daveabrock.com">writes about microservices</a>.</li><li>Mark Seemann <a href="https://blog.ploeh.dk/2021/03/15/pendulum-swing-pure-by-default/?ref=daveabrock.com">writes about using pure functions by default</a>.</li><li>Amy Rigby <a href="https://blog.trello.com/every-successful-person-has-in-common?ref=daveabrock.com">writes how consistency can make you successful</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/03/17/the-authentication-pyramid/?ref=daveabrock.com">writes about the authentication pyramid</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Complete Developer podcast <a href="https://completedeveloperpodcast.com/metacoding-coding-code-analyzers/?ref=daveabrock.com">talks about coding coding analyzers</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-187-agile-conversations-with-fredrick-squirrel/?ref=daveabrock.com">has agile conversations with Fredrick &amp; Squirrel</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/richard-campbell-on-the-humanitarian-toolbox-episode-132?ref=daveabrock.com">talks to Richard Campbell on the Humanitarian Toolbox</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1731&ref=daveabrock.com">talks about MongoDB in the cloud</a>.</li><li>RunAsRadio <a href="http://www.runasradio.com/default.aspx?ShowNum=767&ref=daveabrock.com">talks to Anna Hoffman about migrating to Azure SQL</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>James Montemagno <a href="https://www.youtube.com/watch?v=a37qBMt0V9w&ref=daveabrock.com">works on HTTP web requests with data caching</a>.</li><li>The ON .NET Show <a href="https://www.youtube.com/watch?v=ef1DK76rseM&ref=daveabrock.com">discussing messaging patterns for .NET developers</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=nZBTW9SnnTw&ref=daveabrock.com">discuss output formatters in ASP.NET Core</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Whats-New-in-Azure-SQL-Auditing?ref=daveabrock.com">recaps what’s new in Azure SQL auditing</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #41: 🎁 Your monthly preview fix has arrived ]]></title>
        <description><![CDATA[ This week, Ignite wraps and we get a new upgrade assistant. ]]></description>
        <link>https://www.daveabrock.com/2021/03/20/dotnet-stacks-41/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe98</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 19 Mar 2021 19:00:00 -0500</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-5.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Did you know <a href="https://www.thestar.com/opinion/star-columnists/2021/03/13/email-anniversary-offers-moment-to-reimagine-a-more-productive-less-stressful-workplace-culture.html?utm_source=Twitter&utm_medium=SocialMedia&utm_campaign=OpinionStaff&utm_content=emailanniversary">e-mail turns 50 this year</a>? Do you remember when in 2004, Bill Gates <a href="https://www.theguardian.com/technology/2004/jan/25/billgates.spam?ref=daveabrock.com">pledged to rid the world of spam emails</a> in two years?</p><ul><li><strong>One big thing</strong>: .NET 6 Preview 2 is here</li><li><strong>The little things</strong>: Azure Functions .NET 5 support goes GA, new .NET APIs coming, event sourcing examples</li><li>Last week in the .NET world</li></ul><h1 id="one-big-thing-net-6-preview-2-is-here">One big thing: .NET 6 Preview 2 is here</h1><p>Last week, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2?ref=daveabrock.com">Microsoft released .NET Preview 2</a>. From here on out, the .NET team will ship a new preview every month until .NET 6 goes live in November 2021. As a reminder, .NET 6 is an LTS release, meaning Microsoft will support it for three years.</p><p>A big focus for .NET 6 is improving the inner loop experience and performance: maximizing developer productivity by optimizing the tools we use. While it’s early <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/?ref=daveabrock.com#theme-improve-net-inner-loop-performance">Stephen Toub writes</a> that the team has trimmed overheads when running <code>dotnet new</code>, <code>dotnet build</code>, and <code>dotnet run</code>. This includes fixing issues where tools were unexpectedly JIT’ing and changing the ASP.NET Razor compiler to use a Roslyn source generator to avoid extra compilation steps. A chart of the drastic build time improvements shows a clean build of Blazor Server decreasing from over 3600 milliseconds to around 1500 milliseconds. If you bundle this with a best-in-class hot reload capability, developers have a lot to be excited about with .NET 6.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The crazy wins that <a href="https://t.co/kdc3WLDiTQ?ref=daveabrock.com">https://t.co/kdc3WLDiTQ</a> Razor is getting by flipping their build to use source generators <a href="https://t.co/woe3LGe8kS?ref=daveabrock.com">pic.twitter.com/woe3LGe8kS</a></p>&mdash; Jared Parsons (@jaredpar) <a href="https://twitter.com/jaredpar/status/1370133973112778753?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 11, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>In .NET 6, you’ll be <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/?ref=daveabrock.com#net-multi-platform-app-ui">hearing a lot about MAUI</a> (Multi-Platform App UI), which is the next iteration of Xamarin.Forms. With MAUI, Xamarin developers can use the latest .NET SDKs for the apps they build. If you aren’t a Xamarin developer, you can still take advantage of MAUI: for example, using MAUI Blazor apps can run natively on Windows and macOS machines. With Preview 2, Microsoft enabled a single-project experience that reduces overhead when running Android, iOS, and macOS apps.</p><p>While .NET library improvements don’t come with the same fanfare, a couple of improvements caught my eye. The <code>System.Text.Json</code> library now has a <code>ReferenceHandler.IgnoreCycles</code> option that allows you to ignore cycles when you serialize a complex object graph—a <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/?ref=daveabrock.com#system-text-json-referencehandler-ignorecycles">big step for web developers</a>. Little by little, Microsoft’s <a href="https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0&ref=daveabrock.com#table-of-differences-between-newtonsoftjson-and-systemtextjson">Newtonsoft comparison chart</a> is getting better. Additionally, a new <code>PriorityQueue&lt;TElement, TPriority&gt;</code> collection enables you to <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/?ref=daveabrock.com#priorityqueue">add new items with a value and a priority</a>.</p><p>Aside from the Razor performance improvements, ASP.NET Core now has <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-2/?ref=daveabrock.com#support-for-custom-event-arguments-in-blazor">support for custom event arguments in Blazor</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-2/?ref=daveabrock.com#css-isolation-for-mvc-views-and-razor-pages">CSS isolation for MVC and Razor Pages</a>, and the ability to <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-2/?ref=daveabrock.com#preserve-prerendered-state-in-blazor-apps">preserve prerendered state in Blazor apps</a>. (And no, AOT is not ready yet—the comment <em>CTRL + F “AOT” 0 results, closes the tab</em> from the last preview <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/?ref=daveabrock.com#comment-8437">is the hardest I’ve laughed in a while</a>.) In Entity Framework Core land, the team is working on preserving the synchronization context in <code>SaveChangesAsync</code>, <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-2/?ref=daveabrock.com#more-flexible-free-text-search">flexible free-text search</a>, and <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-2/?ref=daveabrock.com#smoother-integration-with-system-linq-async">smoother integration with <code>System.Linq.Async</code></a>.</p><p>If you want the full details on what’s new in Preview 2, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2?ref=daveabrock.com">Richard Lander has it all</a>. You can also check out <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-2?ref=daveabrock.com">what’s new in ASP.NET Core</a> and <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-2?ref=daveabrock.com">Entity Framework Core as well</a>.</p><h1 id="the-little-things-azure-functions-net-5-support-goes-ga-new-net-apis-coming-event-sourcing-examples">The little things: Azure Functions .NET 5 support goes GA, new .NET APIs coming, event sourcing examples</h1><p>I’ve mentioned this a few times before, but the Azure Functions team has developed a new out-of-process worker that will help with quicker support of .NET versions. Here’s the gist of why they are decoupling a worker from the host, <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/net-on-azure-functions-roadmap/ba-p/2197916?ref=daveabrock.com">from Anthony Chu</a>:</p><blockquote>The Azure Functions host is the runtime that powers Azure Functions and runs on .NET and .NET Core. Since the beginning, .NET and .NET Core function apps have run in the same process as the host. Sharing a process has enabled us to provide some unique benefits to .NET functions, most notably is a set of rich bindings and SDK injections. … However, sharing the same process does come with some tradeoffs. In earlier versions of Azure Functions, dependencies could conflict. While flexibility of packages was largely addressed in Azure Functions V2 and beyond, there are still restrictions on how much of the process is customizable by the user. Running in the same process also means that the .NET version of user code must match the .NET version of the host. These tradeoffs of sharing a process motivated us to choose an out-of-process model for .NET 5.</blockquote><p>A few weeks ago, <a href="https://daveabrock.com/2021/02/24/functions-dotnet-5?ref=daveabrock.com">I wrote about</a> how you can use this with .NET 5 today, but it was very much in preview and involved a lot of manual work. This week, it became production-ready. .NET 6 will support both the in-process and out-of-process options so that .NET Core 3.1 can remain supported. Long term (for .NET 7 and beyond), the team hopes to move new feature capabilities to the out-of-process worker completely—allowing support of .NET 7 on Day 1 from only the isolated worker.</p><hr><p>The .NET team <a href="https://github.com/dotnet/runtime/issues/31525?ref=daveabrock.com">approved a proposal for a new Timer API</a>. As ASP.NET Core architect David Fowler notes in the issue, the current implementation can incur overlapping callbacks (which aren’t async). Additionally, he notes it always captures the execution context, which can cause problems for long-lived operations. How will this new API help? It pauses when user code is executing while resuming the next period when it ends, can be stopped using a <code>CancellationToken</code>, and doesn’t capture an execution context. If you’re only firing a timer once, <code>Task.Delay</code> will continue to be a better option.</p><p>Also, .NET is <a href="https://github.com/dotnet/runtime/issues/47525?ref=daveabrock.com#issuecomment-794272772">getting a new <code>Task.WaitAsync</code> API</a>. This appears to replace <code>WhenAny</code>, allowing Microsoft to assure us that naming things is still the hardest part of computer science. I say call it <code>WhenAsync</code>. If you look at the name hard enough after a few drinks, <code>WhenAny</code> is still there.</p><hr><p>If you’re into event sourcing, check out <a href="https://github.com/oskardudycz/EventSourcing.NetCore?ref=daveabrock.com">Oskar Dudycz’s EventSourcing.NetCore repo</a>. It’s full of nice tutorials and practical examples. That’s all.</p><hr><p>Lastly, a nice tip on how you can tell when a site’s static file was last updated (even if several factors can make this unpredictable).</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Did you know web servers tell you when a static file on a website was last updated? There&#39;s a LOT of caveats since many things can influence this timestamp, do NOT blindly trust it, but it can be helpful.<br><br>F12 &gt; Network &gt; Select file in list &gt; Headers<br><br>Look for &quot;last-modified&quot; <a href="https://t.co/8WGRyfQeGe?ref=daveabrock.com">pic.twitter.com/8WGRyfQeGe</a></p>&mdash; SwiftOnSecurity (@SwiftOnSecurity) <a href="https://twitter.com/SwiftOnSecurity/status/1370586569397186563?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 13, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2?ref=daveabrock.com">announces .NET 6 Preview 2</a>. Daniel Roth <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-2?ref=daveabrock.com">writes about ASP.NET Core updates</a> and Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-2?ref=daveabrock.com">updates us on Entity Framework Core</a>.</li><li>Elton Stoneman <a href="https://blog.sixeyed.com/you-cant-always-have-kubernetes-running-containers-in-azure-vm-scale-sets/?ref=daveabrock.com">runs containers in Azure VM Scale Sets instead of using Kubernetes</a>.</li><li>Sudhir Jonathan <a href="https://sudhir.io/the-big-little-guide-to-message-queues/?ref=daveabrock.com">writes a big little guide to message queues</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/03/11/net-6-preview-2.aspx?ref=daveabrock.com">writes about MAUI support with .NET 6 Preview 2</a>.</li><li>Angelos Petropoulos <a href="https://devblogs.microsoft.com/visualstudio/whats-new-with-github-actions-tooling-in-visual-studio?ref=daveabrock.com">writes about what’s new with GitHub Actions tooling in Visual Studio</a>.</li><li>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/net-on-azure-functions-roadmap/ba-p/2197916?ref=daveabrock.com">provides an update on .NET Azure Functions support</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>For community standups: the EF team <a href="https://www.youtube.com/watch?v=oZVsZrFKp48&ref=daveabrock.com">talks to Julie Lerman</a>, ASP.NET <a href="https://www.youtube.com/watch?v=gRg0xxK8L6w&ref=daveabrock.com">discusses contributing to Blazor</a>, and the Languages &amp; Runtime team <a href="https://www.youtube.com/watch?v=lzyWFew_w8Y&ref=daveabrock.com">discusses the C# design process</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=8cyumKVEth0&ref=daveabrock.com">talks with Yair Halberstadt about compile-time DI</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/03/10/blazor-form-component-validation/?ref=daveabrock.com">works with Blazor form validation</a>.</li><li>Madhu Sudhanan P <a href="https://www.syncfusion.com/blogs/post/build-blazor-crud-application-with-dapper.aspx?ref=daveabrock.com">builds a Blazor app with Dapper</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Mar/09/Role-based-JWT-Tokens-in-ASPNET-Core?ref=daveabrock.com">writes about role-based JWT tokens in ASP.NET Core</a>, and Jason Farrell <a href="https://jfarrell.net/2021/03/09/manual-jwt-validation-in-net-core/?ref=daveabrock.com">performs manual JWT validation in .NET Core</a>.</li><li>The Code Maze blog <a href="https://code-maze.com/benchmarking-csharp-and-asp-net-core-projects/?ref=daveabrock.com">introduces benchmarking C# and ASP.NET Core projects</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/community-question-working-with-data-in-an-http-api?ref=daveabrock.com">answers a question about working with data in an HTTP API</a>, and also <a href="https://khalidabuhakmeh.com/hosting-two-aspnet-core-apps-in-one-host?ref=daveabrock.com">hosts two ASP.NET Core apps in one host</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/03/08/securing-blazor-web-assembly-using-cookies/?ref=daveabrock.com">secures Blazor WebAssembly using cookies</a>.</li><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/03/09/using-alba-to-test-asp-net-services/?ref=daveabrock.com">uses Alba to integration test ASP.NET services</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/real-time-winui-dashboard-with-signalr-backend?ref=daveabrock.com">works on a real-time WinUI dashboard with  a SignalR backend</a>.</li><li>Matthew Jones <a href="https://exceptionnotfound.net/blackjack-in-blazor-part-4-putting-it-all-together/?ref=daveabrock.com">wraps up building a blackjack game in Blazor</a>.</li><li>Aleksandr Hovhannisyan <a href="https://www.aleksandrhovhannisyan.com/blog/why-i-dont-like-tailwind-css/?ref=daveabrock.com">writes about why he doesn’t like Tailwind</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Mark Downie <a href="https://www.poppastring.com/blog/why-we-need-the-rundown-provider?ref=daveabrock.com">writes about the rundown provider</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/03/10/upgrade-assistant.aspx?ref=daveabrock.com">writes about the new .NET Upgrade Assistant</a>.</li><li>Arthur Casals <a href="https://www.infoq.com/news/2021/03/msft-project-reunion-05-preview/?ref=daveabrock.com">writes about Project Reunion 0.5 Preview</a>.</li><li>Konrad Kokosa <a href="https://tooslowexception.com/net-debugging-in-a-single-picture/?ref=daveabrock.com">shows .NET debugging in a single picture</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/run-node-js-14-in-azure-functions/ba-p/2195063?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">writes about running Node.js 14 with Azure Functions</a>.</li><li>James Randall <a href="https://www.azurefromthetrenches.com/comparative-performance-of-azure-functions-and-aws-lambda/?ref=daveabrock.com">compares performance between AWS Lambda and Azure Functions</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/penny-pinching-in-the-cloud-azure-static-web-apps-are-saving-me-money?ref=daveabrock.com">starts using Azure Static Web Apps</a>.</li><li>Johnny Reilly <a href="https://blog.johnnyreilly.com/2021/03/managed-identity-azure-sql-and-entity.html?ref=daveabrock.com">uses Managed Identity, Azure SQL and Entity Framework</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Jiří Činčura <a href="https://www.tabsoverspaces.com/233854-configureawaitchecker-with-support-for-await-using-and-await-foreach?ref=daveabrock.com">shows off ConfigureAwaitChecker with support for “await using” and “await foreach” </a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/download-the-right-chromedriver-version-and-keep-it-up-to-date-on-windows-linux-macos-using-csharp-dotnet?ref=daveabrock.com">downloads the right ChromeDriver version and uses C# to keep it up to date on Windows, Linux, and macOS</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/03/11/c-9-0-covariant-return-types/?ref=daveabrock.com">writes about covariant return types in C# 9</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/five-csharp-features-you-dont-know/?ref=daveabrock.com">writes about five C# features you might not know about</a>.</li><li>Jeff Fritz <a href="https://dev.to/dotnet/my-favorite-c-features-part-2-linq-57kd?ref=daveabrock.com">writes about LINQ</a>.</li><li>Mark Seemann <a href="https://blog.ploeh.dk/2021/03/08/pendulum-swing-sealed-by-default/?ref=daveabrock.com">uses sealed by default, for C# classes</a>.</li><li>Munib Butt <a href="https://www.c-sharpcorner.com/article/pattern-matching-in-c-sharp/?ref=daveabrock.com">writes about pattern matching in C#</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Upgrade-Interfaces-Without-Breaking-Existing-Code?ref=daveabrock.com">writes about default interface implementations in C#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/dont-forget-about-the-github-command-line?ref=daveabrock.com">shows off the GitHub command line</a>.</li><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/blinking-leds-with-raspberry-pi?ref=daveabrock.com">uses blinking APIs with Raspberry Pi and .NET</a>.</li><li>Check out <a href="https://ohmygit.org/?ref=daveabrock.com">Oh My Git, a fun way to learn the ins and outs of Git</a>.</li><li>Mislav Marohnić <a href="https://github.blog/2021-03-11-scripting-with-github-cli/?ref=daveabrock.com">scripts with the GitHub CLI</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/installing-docker-desktop-for-windows/?ref=daveabrock.com">installs Docker Desktop for Windows and WSL 2</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/621/building-and-auto-deploying-an-aspnet-core-application-part-4-setting-up-a-ci-pipeline-in-azure-devops-to-build-and-test-your-code?ref=daveabrock.com">sets up a CI pipeline in Azure DevOps to build and test code</a>.</li><li>Oskar Duducz <a href="https://github.com/oskardudycz/EventSourcing.NetCore?ref=daveabrock.com">has a GitHub repo showing off examples and resources for using event sourcing in .NET Core</a>.</li><li>Regis Wilson asks: <a href="https://dev.to/rwilsonrelease/why-is-kubernetes-so-hard-i42?ref=daveabrock.com">why is Kubernetes so hard?</a>.</li><li>Neel Bhatt <a href="https://neelbhatt.com/2021/03/07/first-look-at-infersharp-a-c-version-of-facebooks-infer/?ref=daveabrock.com">takes a look at InferSharp</a>.</li><li>Laurent Kempé <a href="https://laurentkempe.com/2021/03/09/getting-started-with-dapr-for-dotnet-developers/?ref=daveabrock.com">gets started with Dapr for .NET developers</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/6-free-tools-for-net-developers/?ref=daveabrock.com">shows off 6 free tools for .NET developers</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/uno-safe-area/?ref=daveabrock.com">converts Xamarin.Forms to WinUI and Uno</a>.</li><li>Selva Ganapathy Kathiresan <a href="https://www.syncfusion.com/blogs/post/advantages-net-maui-over-xamarin.aspx?ref=daveabrock.com">writes about the advantages of using MAUI over Xamarin</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Uduak Obong-Eren <a href="https://meekg33k.dev/6-red-flags-i-saw-while-doing-60-technical-interviews-in-30-days-ckm53wt5f00avscs13xf9fhcs?ref=daveabrock.com">writes about red flags to look out for while interviewing</a>.</li><li>Mauro Servienti <a href="https://milestone.topics.it/2021/03/10/not-all-changes-are-born-equal.html?ref=daveabrock.com">writes about how not all changes are equal</a>.</li><li>The ThoughtWorks blog <a href="https://www.thoughtworks.com/insights/blog/shift-mindset-needed-kubernetes-adoption-part-2?ref=daveabrock.com">continues writing about Kubernetes adoption best practices</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/193409-B/the-coding-interview-that-i-failed?Key=91893b7f-c17a-4135-ae0e-6315cfde09aa&ref=daveabrock.com">writes about a coding interview that he failed</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1730&ref=daveabrock.com">talks to Daniel Roth about .NET 6</a>.</li><li>The Xamarin Podcast <a href="https://www.xamarinpodcast.com/88?ref=daveabrock.com">offers an update on MAUI</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-059-blazor-keeps-getting-better-with-daniel-roth/?ref=daveabrock.com">talks to Daniel Roth about Blazor</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/244?ref=daveabrock.com">introduces microservices</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-186-gitops-with-kelsey-hightower/?ref=daveabrock.com">talks GitOps with Kelsey Hightower</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>James Montemagno <a href="https://www.youtube.com/watch?v=zvPPz6DABi8&ref=daveabrock.com">discusses whether you should develop in Xamarin today or wait for MAUI</a>.</li><li>Scott Hanselman and Azure Barry <a href="https://channel9.msdn.com/Shows/Azure-Friday/What-to-use-for-monitoring-your-applications-in-Azure?ref=daveabrock.com">discuss what to use for monitoring your applications in Azure</a>, and also <a href="https://channel9.msdn.com/Shows/Azure-Friday/What-to-use-for-deploying-and-testing-your-applications-in-Azure?ref=daveabrock.com">discuss what to use for deploying and testing your applications in Azure</a>.</li><li>The ON .NET Show <a href="https://dev.to/dotnet/on-net-episode-building-microservices-with-tye-3ci?ref=daveabrock.com">builds microservices with Tye</a>, and also <a href="https://www.youtube.com/watch?v=ysxgpVfyeNA&ref=daveabrock.com">discusses commands, queries, and other fun architectural patterns</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Add a shared dialog component ]]></title>
        <description><![CDATA[ In this post, we add a dialog to get a closer look at our images. ]]></description>
        <link>https://www.daveabrock.com/2021/03/17/blast-off-blazor-add-dialog/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe97</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 16 Mar 2021 19:00:00 -0500</pubDate>
        <media:content url="https://images.unsplash.com/photo-1461354464878-ad92f492a5a0?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDN8fHNoYXJlfGVufDB8fHx8MTYxOTgyODY2MA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>, <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolated our service dependencies</a>, worked on <a href="https://daveabrock.com/2020/12/13/blast-off-blazor-cosmos?ref=daveabrock.com">hosting our images over Azure Blob Storage and Cosmos DB</a>, <a href="https://daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery?ref=daveabrock.com">built a responsive image gallery</a>, and <a href="https://daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm?ref=daveabrock.com">implemented prerendering</a>, and <a href="https://daveabrock.com/2021/01/14/blast-off-blazor-search-box?ref=daveabrock.com">built a search-as-you-type box</a>.</p><p>With our card layout all set and searchable, we can now build a shared dialog component. In this dialog, users can click a card to get more details about the image. The dialog will display the title, date, an explanation, the photo itself, and a link where users can open the image from my public Azure Blob Storage container.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/blast-off-dialog.jpg" class="kg-image" alt="The new dialog" loading="lazy" width="1237" height="1100" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/blast-off-dialog.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/blast-off-dialog.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/blast-off-dialog.jpg 1237w" sizes="(min-width: 720px) 720px"></figure><p>While building a dialog yourself seems straightforward, many nuances can make it a pain to write yourself. You’ve got to apply CSS effects (like dim the background when it’s opened), make it scrollable, have it adapt to multiple screen sizes, allow keyboard input (like closing the dialog when you hit the <code>Esc</code> key), and so on. While there are many great options out there, I decided to use the <a href="https://mudblazor.com/?ref=daveabrock.com">MudBlazor component library</a>.</p><p>Let’s get started. As always, my <a href="https://github.com/daveabrock/NASAImageOfDay?ref=daveabrock.com">project is out on GitHub</a>.</p><h2 id="install-and-configure-mudblazor">Install and configure MudBlazor</h2><p>To install MudBlazor, I ran the following <code>dotnet</code> CLI command from my <code>BlastOff.Client</code> project:</p><pre><code>dotnet add package MudBlazor
</code></pre><p>To prevent manual imports across the component files, I added a single <code>@using</code> at the <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/_Imports.razor?ref=daveabrock.com#L13">bottom of my <code>_Imports.razor</code> file</a>.</p><pre><code>@using MudBlazor
</code></pre><p>Then, <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Program.cs?ref=daveabrock.com#L21-L22">in <code>Program.cs</code> in the <code>BlastOff.Client</code> project</a>, add the following services:</p><pre><code class="language-csharp">using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using MudBlazor.Services;

namespace BlastOff.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add&lt;App&gt;("#app");

            // other stuff not relevant to this post

            builder.Services.AddMudServices();
            builder.Services.AddMudBlazorDialog();

            await builder.Build().RunAsync();
        }
    }
}
</code></pre><p>In the project’s <code>wwwroot/index.html</code>, <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/wwwroot/index.html?ref=daveabrock.com#L18">add MudBlazor’s CSS in the <code>&lt;head&gt;</code> tag</a> and its JS before the end of the <code>&lt;body&gt;</code> tag. (By the way, this is all <a href="https://mudblazor.com/getting-started/installation?ref=daveabrock.com">in the MudBlazor documentation</a>.)</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;!-- Condensed &lt;head&gt; --&gt;
        &lt;link href="BlastOff.Client.styles.css" rel="stylesheet"&gt;
        &lt;link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" /&gt;
    &lt;/head&gt;

    &lt;body&gt;
    &lt;!-- Condensed &lt;body&gt; --&gt;
    &lt;script src="_framework/blazor.webassembly.js"&gt;&lt;/script&gt;
    &lt;script src="_content/MudBlazor/MudBlazor.min.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre><p>To complete MudBlazor setup, add a <code>MudThemeProvider</code> and <code>MudDialogProvider</code> component <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Shared/MainLayout.razor?ref=daveabrock.com#L7-L10">in the <code>Shared/MainLayout.razor</code> file</a>. You’ll notice I can also pass global dialog parameters, like <code>FullWidth</code> and <code>MaxWidth</code>.</p><pre><code class="language-html">@inherits LayoutComponentBase
&lt;NavBar /&gt;

&lt;div&gt;
    &lt;div class="section columns"&gt;
        &lt;main class="column"&gt;
            &lt;MudThemeProvider/&gt;
            &lt;MudDialogProvider
                FullWidth="true"
                MaxWidth="MaxWidth.Small"/&gt;
            @Body
        &lt;/main&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre><h2 id="add-the-shared-dialog-component">Add the shared dialog component</h2><p>With MudBlazor set up and configured, let’s add a new dialog component in <code>Shared/ImageDialog.razor</code>.</p><p>In <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Shared/ImageDialog.razor?ref=daveabrock.com#L26-L32">the <code>@code</code> block</a>, we first need to wire up <code>Submit</code> and <code>Cancel</code> events. The <code>Submit</code> will be bound to a simple <code>Ok</code> dialog result, and the <code>Cancel</code> will assume the default behavior. MudBlazor passes down a <code>CascadingParameter</code> of a <code>MudDialog</code>. I’m also passing down <code>ImageDetails</code> as a parameter containing the data I’m using to populate the dialog.</p><pre><code class="language-csharp">@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public Image ImageDetails { get; set; }

    void Submit() =&gt; MudDialog.Close(DialogResult.Ok(true));
    void Cancel() =&gt; MudDialog.Cancel();
}
</code></pre><p>In <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Shared/ImageDialog.razor?ref=daveabrock.com#L1-L23">the markup</a>, the <code>ImageDetails</code> model will live inside a <code>MudDialog</code> and the associated <code>DialogContent</code> and, finally, a <code>MudContainer</code>. After some simple Tailwind CSS styling, I’m using <code>ImageDetails</code> properties to populate my dialog.</p><pre><code class="language-html">&lt;MudDialog&gt;
    &lt;DialogContent&gt;
        &lt;MudContainer Style="max-height: 500px; overflow-y: scroll"&gt;
            &lt;div class="text-gray-600 text-md-left font-semibold tracking-wide"&gt;
                @ImageDetails.PrettyDate
            &lt;/div&gt;
            &lt;div class="text-xs p-4"&gt;
                @ImageDetails.Explanation
            &lt;/div&gt;
            &lt;div class="p-4"&gt;
                &lt;a href="@ImageDetails.Url" target="_blank"&gt;See high-quality image &lt;i class="fa fa-external-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;img src="@ImageDetails.Url" /&gt;
        &lt;/MudContainer&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton OnClick="Cancel"&gt;Cancel&lt;/MudButton&gt;
        &lt;MudButton Color="Color.Primary" OnClick="Submit"&gt;Ok&lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;
</code></pre><h2 id="add-dialog-to-imagecard">Add dialog to <code>ImageCard</code></h2><p>With the shared dialog created, now let’s <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Pages/ImageCard.razor?ref=daveabrock.com#L32-L42">add it to our existing <code>ImageCard</code> component</a>. For the markup, we can inject an <code>IDialogService</code> and also <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Pages/ImageCard.razor?ref=daveabrock.com#L2">bind an <code>OpenDialog</code> function to an <code>@onclick</code> event</a>.</p><pre><code class="language-html">@inject IDialogService DialogService
&lt;div class="image-container m-6 rounded overflow-hidden shadow-lg"
     @onclick="OpenDialog"&gt;

    &lt;!-- All the existing markup --&gt;
&lt;/div&gt;
</code></pre><p>The <code>@code</code> block includes the <code>ImageDetails</code> as a parameter to send to the dialog. Then, in <code>OpenDialog</code>, pass the <code>ImageDetails</code> into <code>DialogParameters</code>, and show the dialog.</p><pre><code class="language-csharp">@code
{
    [Parameter]
    public Image ImageDetails { get; set; }

    private void OpenDialog()
    {
        var parameters = new DialogParameters {{"ImageDetails", ImageDetails}};
        DialogService.Show&lt;ImageDialog&gt;(ImageDetails.Title, parameters);
    }
}
</code></pre><h2 id="bonus-use-css-isolation-for-image-card-hover-effect">Bonus: Use CSS isolation for image card hover effect</h2><p>I added a hover effect, where image cards get <em>just a little bit bigger</em> as you hover over them. It’s a simple and subtle way to tell users, <em>Hey, you can click on this.</em></p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/transform-scale.jpg" class="kg-image" alt="Transform the image card with CSS" loading="lazy" width="1257" height="977" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/transform-scale.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/transform-scale.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/transform-scale.jpg 1257w" sizes="(min-width: 720px) 720px"></figure><p>I’ve written a <a href="https://daveabrock.com/2020/09/10/blazor-css-isolation?ref=daveabrock.com">few</a> <a href="https://daveabrock.com/2021/01/31/blazor-css-iso-inheritance-scopes?ref=daveabrock.com">times</a> about <a href="https://docs.microsoft.com/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0&ref=daveabrock.com">Blazor CSS isolation</a>. You can check out the links for details, but it allows you to scope styles to a specific component only.</p><p>To do this, I <a href="https://github.com/daveabrock/NASAImageOfDay/blob/main/BlastOff.Client/Pages/ImageCard.razor.css?ref=daveabrock.com">created an <code>ImageCard.razor.css</code> file</a>. The style makes the image card 10% bigger on hover.</p><pre><code class="language-css">.image-container:hover {
    transform: scale(1.10)
}
</code></pre><p>Mission complete!</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we used the MudBlazor component library to create a shared dialog component. We showed how to install and configure the library, create the component, and add it to our existing solution. As a bonus, we used CSS isolation to apply a nice hover effect.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use C# to upload files to a GitHub repository ]]></title>
        <description><![CDATA[ In this post, let&#39;s use the Octokit library to use C# to upload files to a GitHub repository. ]]></description>
        <link>https://www.daveabrock.com/2021/03/14/upload-files-to-github-repository/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe96</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 13 Mar 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1590595906931-81f04f0ccebb?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGdpdGh1YnxlbnwwfHx8fDE2MTk4Mjg3MTc&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>If you need to upload a file to GitHub, <a href="https://docs.github.com/en/github/managing-files-in-a-repository/adding-a-file-to-a-repository?ref=daveabrock.com">you can do it easily</a> from <em>github.com</em>. However, that doesn’t scale. When it comes to doing it on a repeated basis or facilitating automation, you’ll want to take a programmatic approach. While GitHub <a href="https://docs.github.com/en/rest?ref=daveabrock.com">does have a REST API</a>, C# developers can take advantage of <a href="https://github.com/octokit/octokit.net?ref=daveabrock.com">the Octokit library</a>. This library saves you a lot of time—you can take advantage of dynamic typing, get data models automatically, and not have to construct <code>HttpClient</code> calls yourself.</p><p>This post will show you how to use the Octokit library to upload a Markdown file to a GitHub repository.</p><p>Before we get started, download the Octokit library from NuGet. You can do this in several different ways, but the simplest is using the <code>dotnet</code> CLI. From the path of your project, execute the following from your favorite terminal:</p><pre><code>dotnet add package Octokit
</code></pre><h2 id="create-the-client">Create the client</h2><p>To get started, you’ll need to create a client so that Octokit can connect to GitHub. To do that, you can instantiate a new <code>GitHubClient</code>. The <code>GitHubClient</code> takes a <code>ProductHeaderValue</code>, which can be any string—it’s so GitHub can identify your application. GitHub doesn’t allow API requests without a <code>User-Agent</code> header, and Octokit uses this value to populate one for you.</p><pre><code class="language-csharp">//using Octokit;

var gitHubClient = new GitHubClient(new ProductHeaderValue("MyCoolApp"));
</code></pre><p>With this single line of code, you can now access public GitHub information. For example, you can use a web browser to get a user’s details. Here’s what you get for <code>api.github.com/users/daveabrock</code>:</p><pre><code class="language-json">{
    "login": "daveabrock",
    "id": 275862,
    "node_id": "MDQ6VXNlcjI3NTg2Mg==",
    "avatar_url": "https://avatars.githubusercontent.com/u/275862?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/daveabrock",
    "html_url": "https://github.com/daveabrock",
    "followers_url": "https://api.github.com/users/daveabrock/followers",
    "following_url": "https://api.github.com/users/daveabrock/following{/other_user}",
    "gists_url": "https://api.github.com/users/daveabrock/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/daveabrock/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/daveabrock/subscriptions",
    "organizations_url": "https://api.github.com/users/daveabrock/orgs",
    "repos_url": "https://api.github.com/users/daveabrock/repos",
    "events_url": "https://api.github.com/users/daveabrock/events{/privacy}",
    "received_events_url": "https://api.github.com/users/daveabrock/received_events",
    "type": "User",
    "site_admin": false,
    "name": "Dave Brock",
    "company": null,
    "blog": "daveabrock.com",
    "location": "Madison, WI",
    "email": null,
    "hireable": null,
    "bio": "Software engineer, Microsoft MVP, speaker, blogger",
    "twitter_username": "daveabrock",
    "public_repos": 55,
    "public_gists": 2,
    "followers": 63,
    "following": 12,
    "created_at": "2010-05-13T20:05:05Z",
    "updated_at": "2021-03-13T19:05:32Z"
}
</code></pre><p>(Fun fact: it’s fun to look at the <code>id</code> values to see how long a user has been with GitHub—I was the 275,862nd registered user, a few years after <a href="https://api.github.com/users/mojombo?ref=daveabrock.com">GitHub co-founder Tom Preston-Warner</a>, who has an <code>id</code> of <code>1</code>.)</p><p>To get this information programmatically, you can use the <code>User</code> object:</p><pre><code class="language-csharp">//using Octokit;

var gitHubClient = new GitHubClient(new ProductHeaderValue("MyCoolApp"));
var user = await gitHubClient.User.Get("daveabrock");
Console.WriteLine($"Woah! Dave has {user.PublicRepos} public repositories.");
</code></pre><p>That was quick and easy, but not very much fun. To modify anything in a repository you’ll need to authenticate.</p><h2 id="authenticate-to-the-api">Authenticate to the API</h2><p>You can authenticate to the API using one of two ways: a basic username/password pair or an OAuth flow. Using OAuth (from a generated personal access token) is almost always a better approach, as you won’t have to store a password in the code, and you can revoke it as needed. What happens when a password changes? Bad, bad, bad.</p><p>Instead, connect by <a href="https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token?ref=daveabrock.com">passing in a personal access token (PAT)</a>. From your profile details, navigate to <strong>Developer settings</strong> &gt; <strong>Personal access tokens</strong>, and create one. You’ll want to include the <code>repo</code> permissions. After you create it, copy and paste the token somewhere. We’ll need it shortly.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/github-pat.jpg" class="kg-image" alt="Generate GitHub personal access token" loading="lazy" width="1880" height="1137" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/github-pat.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/github-pat.jpg 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/github-pat.jpg 1600w, https://www.daveabrock.com/content/images/2021/05/github-pat.jpg 1880w" sizes="(min-width: 720px) 720px"></figure><p>With the generated PAT, here’s how you authenticate to the API. (<strong>Note</strong>: Be careful with your token. In real-world scenarios, make sure to store it somewhere safe and access it from your configuration.)</p><pre><code class="language-csharp">//using Octokit;

var gitHubClient = new GitHubClient(new ProductHeaderValue("MyCoolApp"));
gitHubClient.Credentials = new Credentials("my-new-personal-access-token");
</code></pre><h2 id="add-a-new-file-to-the-repository">Add a new file to the repository</h2><p>With that in place, I’m using a <code>StringBuilder</code> to create a simple Markdown file. Here’s what I have so far:</p><pre><code class="language-csharp">//using Octokit;

var gitHubClient = new GitHubClient(new ProductHeaderValue("MyCoolApp"));
gitHubClient.Credentials = new Credentials("my-new-personal-access-token");

var sb = new StringBuilder("---");
sb.AppendLine();
sb.AppendLine($"date: \"2021-05-01\"");
sb.AppendLine($"title: \"My new fancy post\"");
sb.AppendLine("tags: [csharp, azure, dotnet]");
sb.AppendLine("---");
sb.AppendLine();

sb.AppendLine("# The heading for my first post");
sb.AppendLine();
</code></pre><p>Because I need to pass in a string to create my file, I’ll use <code>sb.ToString()</code>, to pass it in. I can call the <code>CreateFile</code> method to upload a file now.</p><pre><code class="language-csharp">//using Octokit;

var gitHubClient = new GitHubClient(new ProductHeaderValue("MyCoolApp"));
gitHubClient.Credentials = new Credentials("my-new-personal-access-token");

var sb = new StringBuilder("---");
sb.AppendLine();
sb.AppendLine($"date: \"2021-05-01\"");
sb.AppendLine($"title: \"My new fancy updated post\"");
sb.AppendLine("tags: [csharp, azure, dotnet]");
sb.AppendLine("---");
sb.AppendLine();

sb.AppendLine("The heading for my first post");
sb.AppendLine();

var (owner, repoName, filePath, branch) = ("daveabrock", "daveabrock.github.io", 
        "_posts/2021-05-02-my-new-post.markdown", "main");

await gitHubClient.Repository.Content.CreateFile(
     owner, repoName, filePath,
     new CreateFileRequest($"First commit for {filePath}", sb.ToString(), branch));    
</code></pre><p>You can fire and forget in many cases, but it’s good to note this method returns a <code>Task&lt;RepositoryChangeSet&gt;</code> which gives you back commit and content details.</p><h2 id="update-an-existing-file">Update an existing file</h2><p>If you try to execute <code>CreateFile</code> on an existing file, you’ll get an error that the SHA for the commit doesn’t exist. You’ll need to fetch the SHA from the result first.</p><pre><code class="language-csharp">var sha = result.Commit.Sha;

await gitHubClient.Repository.Content.UpdateFile(owner, repoName, filePath,
    new UpdateFileRequest("My updated file", sb.ToString(), sha));
</code></pre><p>In many scenarios, you won’t be editing the file right after you created it. In these cases, get the file details first:</p><pre><code class="language-csharp">var fileDetails = await gitHubClient.Repository.Content.GetAllContentsByRef(owner, repoName,
    filePath, branch);

var updateResult = await gitHubClient.Repository.Content.UpdateFile(owner, repoName, filePath,
    new UpdateFileRequest("My updated file", sb.ToString(), fileDetails.First().Sha));
</code></pre><h2 id="what-about-base64">What about base64?</h2><p>The <code>CreateFile</code> call also has a <code>convertContentToBase64</code> boolean flag, if you’d prefer. For example, I can pass in an image’s base64 string and set <code>convertContentToBase64</code> to <code>true</code>.</p><pre><code class="language-csharp">string imagePath = @"C:\pics\headshot.jpg";
string base64String = GetImageBase64String(imagePath);

var result = await gitHubClient.Repository.Content.CreateFile(
     owner, repoName, filePath,
     new CreateFileRequest($"First commit for {filePath}", base64String, branch, true));

static string GetImageBase64String(string imgPath)
{
    byte[] imageBytes = System.IO.File.ReadAllBytes(imgPath);
    return Convert.ToBase64String(imageBytes);
}
</code></pre><h2 id="wrap-up">Wrap up</h2><p>I showed you how to use the Octokit C# library to upload a new file to GitHub in this post. We also discussed how to update existing files and pass base64 strings to GitHub as well. Thanks for reading, and have fun!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #40: 📚 Ignite is in the books ]]></title>
        <description><![CDATA[ This week, Ignite wraps and we get a new upgrade assistant. ]]></description>
        <link>https://www.daveabrock.com/2021/03/13/dotnet-stacks-40/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe95</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 12 Mar 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-6.png" medium="image"/>
        <content:encoded><![CDATA[ <p>We’ve made it to 40. Does this mean we’re over the hill?</p><ul><li><strong>One big thing</strong>: Ignite recap</li><li><strong>The little things</strong>: a new upgrade assistant, Okta buys Auth0, hash codes</li><li>Last week in the .NET world</li></ul><h1 id="one-big-thing-ignite-recap">One big thing: Ignite recap</h1><p>Microsoft <a href="https://myignite.microsoft.com/home?ref=daveabrock.com">held Ignite this week</a>. If you’re looking for splashy developer content, don’t hold your breath—that’s more suited for Build. Still, it’s an excellent opportunity to see what Microsoft is prioritizing. While most of this section won’t be pure .NET content, it’s still valuable (especially if you deploy to Azure). You can read a rundown of key announcements in the <a href="https://news.microsoft.com/ignite-march-2021-book-of-news/?ref=daveabrock.com">Book of News</a>, and you can also <a href="https://www.youtube.com/watch?v=VjR09KSMDKg&list=PLQXpv_NQsPIALDgjX4bEmxxjMtuDir6ra&ref=daveabrock.com">hit up the YouTube playlist</a>.</p><p>A big part of the VR-friendly keynote involved Satya Nadella sharing the virtual stage with Microsoft Mesh, the new mixed-reality platform. From the <em>Book of News</em>, it “powers collaborative experiences with a feeling of presence–meaning users feel like they are physically present with one another even when they are not.” Folks can interact with 3D objects and other people through Mesh-enabled apps across a wide variety of devices. If this is where you say, <em>Dave, this a .NET newsletter</em> - noted. However, as a technology that received attention at the Ignite keynote, it bears mention. (Especially with its applications in today’s pandemic world.)</p><p>If you’re into Azure Cognitive Services, Microsoft rolled out <a href="https://www.microsoft.com/research/blog/the-science-behind-semantic-search-how-ai-from-bing-is-powering-azure-cognitive-search/?ref=daveabrock.com">semantic capabilities</a>. Also, their Form Recognizer service now has support for ID documents and invoice extraction. There are new Enterprise tiers for Azure Cache for Redis, and Azure Cosmos DB now has continuous backup and point-in-time support.</p><p>Azure Communication Services, announced last fall, is hitting general availability in a few weeks. If you aren’t familiar with it, Azure Communication Services allows developers to integrate voice, video, and text communication with their apps. (It certainly makes the relationship with Twilio a little more interesting.) The power of having these capabilities in Azure gives it the ability to integrate with other Azure products and services. For example, Azure Bot Service has a new telephony channel built on Azure Communication Services. If you’re writing a bot, you can leverage the AI from Cognitive Services and integrate it with your phone and messaging capabilities. These capabilities provide a distinct advantage to other services that focus on one need.</p><h1 id="the-little-things-a-new-upgrade-assistant-okta-buys-auth0-hash-codes">The little things: a new upgrade assistant, Okta buys Auth0, hash codes</h1><p>This week, Microsoft announced <a href="https://devblogs.microsoft.com/dotnet/introducing-the-net-upgrade-assistant-preview/?ref=daveabrock.com">the .NET Upgrade Assistant</a>, a <a href="https://dotnet.microsoft.com/platform/upgrade-assistant?ref=daveabrock.com">global tool</a> that promises to help you upgrade your .NET Framework-based applications to .NET 5. It’s a global CLI tool that offers a guided experience for “incrementally updating your applications.” The assistant determines which projects you need to upgrade and recommends the order to be upgraded. Unlike tools like try-convert, you can see recommendations and choose how to upgrade your code.</p><p>The .NET Upgrade Assistant is not a tool meant to upgrade with a click of a button—you’ll likely need to do some manual work. It does promise to make your upgrade experience a lot easier. You can <a href="https://github.com/dotnet/upgrade-assistant?ref=daveabrock.com">check out the GitHub repo</a> for details as well. Side note: I’ll be releasing a detailed post on the .NET Upgrade Assistant by month’s end.</p><hr><p>Last week, Okta <a href="https://techcrunch.com/2021/03/03/okta-acquires-cloud-identity-startup-auth0-for-6-5b/?ref=daveabrock.com">bought Auth0 for $6.5 billion</a>. (I think I need to start an API company.)</p><p>It makes sense: at the risk of oversimplifying, Okta provides IAM to companies that use it for SSO. Auth0 works on the app level, allowing developers API access to SSO. Okta has a reputation for being very enterprise-<em>y</em>, and Auth0 is known as a company with a startup feel that provides a developer-first experience. With this news, IdentityServer v4 now a paid product, and the Azure AD offerings, you have many choices when it comes to integrating auth in your .NET apps.</p><hr><p>Did you know about <code>HashCode.Combine</code>? If you’re using custom <code>GetHashCode</code> implementations and C# 9 records don’t suit your needs it makes overriding hash codes easier.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I had no idea this feature existed in .NET - HashCode.Combine, for custom GetHashCode implementations. No more fancy bitwise operations needed to do this anymore. <a href="https://t.co/x0DHiqeCpx?ref=daveabrock.com">https://t.co/x0DHiqeCpx</a> <a href="https://t.co/net5avsZTd?ref=daveabrock.com">pic.twitter.com/net5avsZTd</a></p>&mdash; Aaron Stannard (@Aaronontheweb) <a href="https://twitter.com/Aaronontheweb/status/1368258898512216065?ref_src=twsrc%5Etfw&ref=daveabrock.com">March 6, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Luis Quintanilla <a href="https://devblogs.microsoft.com/dotnet/serve-ml-net-models-as-http-apis-with-minimal-configuration?ref=daveabrock.com">serves ML.NET models as HTTP APIs with minimal configuration</a>.</li><li>Isaac Abraham <a href="https://devblogs.microsoft.com/azure-sdk/azure-solutions-azure-sdk-fsharp-farmer?ref=daveabrock.com">creates Azure solutions with the new Azure SDKs, F#, and Farmer</a>.</li><li>Microsoft <a href="https://devblogs.microsoft.com/dotnet/introducing-the-net-upgrade-assistant-preview?ref=daveabrock.com">announces the .NET Upgrade Assistant, now in preview</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Phillip Carter <a href="https://devblogs.microsoft.com/dotnet/f-and-f-tools-update-for-visual-studio-16-9?ref=daveabrock.com">writes about F# and F# tools updates for Visual Studio 16.9</a>.</li><li>Maria Naggaga <a href="https://devblogs.microsoft.com/dotnet/net-interactive-with-sql-net-notebooks-in-visual-studio-code?ref=daveabrock.com">announces .NET Interactive with SQL</a>.</li><li>.NET Core 2.1 <a href="https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021?ref=daveabrock.com">will reach End of Support on August 21</a>.</li><li>Visual Studio 2019 <a href="https://devblogs.microsoft.com/visualstudio/vs2019-v16-9-and-v16-10-preview-1?ref=daveabrock.com">v16.9 and v16.10 Preview are now available</a>, and Peter Groenewegen <a href="https://devblogs.microsoft.com/visualstudio/repeated-edits-intellicode-suggestions-completion-list?ref=daveabrock.com">writes about IntelliCode suggestions in completion lists in the new version</a>.</li><li>Visual Studio 2019 <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-version-8-9-is-now-available?ref=daveabrock.com">for Mac version 8.9 is now available</a>.</li><li>Jiachen Jiang <a href="https://devblogs.microsoft.com/nuget/state-of-the-nuget-ecosystem?ref=daveabrock.com">writes about the state of the NuGet ecosystem</a>, then Drew Gillies <a href="https://devblogs.microsoft.com/nuget/how-to-scan-nuget-packages-for-security-vulnerabilities?ref=daveabrock.com">explains how to scan NuGet packages for security vulnerabilities</a>.</li><li>Kayla Cinnamon <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-7-release?ref=daveabrock.com">releases Windows Terminal Preview 1.7</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>The Ignite 2021 <a href="https://www.youtube.com/watch?v=VjR09KSMDKg&list=PLQXpv_NQsPIALDgjX4bEmxxjMtuDir6ra&ref=daveabrock.com">playlist is here</a>.</li><li>Scott Addie <a href="https://docs.microsoft.com/aspnet/core/whats-new/2021-02?view=aspnetcore-5.0&ref=daveabrock.com">writes about what’s new in the ASP.NET Core docs</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=j18TR2YKKOg&ref=daveabrock.com">talks about home automation</a>.</li><li>Microsoft publishes the <a href="https://news.microsoft.com/ignite-march-2021-book-of-news/?ref=daveabrock.com">Book of News for the Ignite conference</a>.</li><li>Jon Galloway <a href="https://devblogs.microsoft.com/dotnet/learn-to-build-http-apis-with-net?ref=daveabrock.com">writes about getting started with writing HTTP APIs in .NET</a>.</li><li>Blazorise <a href="https://blazorise.com/news/release-notes/093/?ref=daveabrock.com">0.9.3 is out</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2021/03/04/free-blazor-crash-course/?ref=daveabrock.com">rolls out a new video series on getting started with Blazor</a>.</li><li>Cecil Phillip <a href="https://channel9.msdn.com/Series/Beginners-Series-to-Web-APIs/What-are-Web-APIs-1-of-18--Beginners-Series-to-Web-APIs?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">rolls out a beginner’s guide to Web APIs</a>.</li><li>For community standups: Xamarin <a href="https://www.youtube.com/watch?v=NEbRo0ltniM&ref=daveabrock.com">talks to Brandon Minnick about GitTrends</a>, Machine Learning <a href="https://www.youtube.com/watch?v=jWr_D_R2nZw&ref=daveabrock.com">talks tooling</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=Qfy467I6Yts&ref=daveabrock.com">talks about Web Live Preview</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Jon Hilton <a href="https://jonhilton.net/razor-pages-components/?ref=daveabrock.com">gives Razor Pages some love</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/configuring-https-with-netlify-and-cloudflare/?ref=daveabrock.com">configures HTTPS using a custom TLS cert with Netlify and Cloudflare</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-httpclientfactory-in-asp-net-core-applications/?ref=daveabrock.com">uses HttpClientFactory in ASP.NET Core apps</a>, and also <a href="https://code-maze.com/canceling-http-requests-in-asp-net-core-with-cancellationtoken/?ref=daveabrock.com">cancels HTTP requests in ASP.NET Core with CancellationToken</a>.</li><li>Grant Hair <a href="https://dev.to/granthair5/a-couple-ways-i-test-my-net-apis-omk?ref=daveabrock.com">talks about how he tests his .NET APIs</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/02/28/refactoring-with-reflection/?ref=daveabrock.com">refactors with reflection</a>.</li><li>Maoni Stephens <a href="https://devblogs.microsoft.com/dotnet/internals-of-the-poh?ref=daveabrock.com">writes about the internals of the pinned object heap (POH)</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/breaking-changes/?ref=daveabrock.com">writes about what’s in store for WinUI, Project Reunion, and MAUI</a>.</li><li>Sagar Shetty <a href="https://devblogs.microsoft.com/visualstudio/new-dynamic-instrumentation-profiling?ref=daveabrock.com">writes about new dynamic instrumentation profiling for .NET</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>The Microsoft Research Blog <a href="https://www.microsoft.com/research/blog/the-science-behind-semantic-search-how-ai-from-bing-is-powering-azure-cognitive-search/?ref=daveabrock.com">writes about how Bing uses semantic search with Azure Cognitive Services</a>.</li><li>Luis Cabrera-Cordon <a href="https://techcommunity.microsoft.com/t5/azure-ai/introducing-semantic-search-bringing-more-meaningful-results-to/ba-p/2175636?ref=daveabrock.com">introduces semantic search for Azure Cognitive Services</a>.</li><li>Graham Else <a href="https://www.twilio.com/blog/appointment-reminders-csharp-aws-lambda-cloudwatch?ref=daveabrock.com">automates appointment reminders in C# using AWS Lambda</a>.</li><li>Abhishek Gupta <a href="https://dev.to/azure/autoscaling-redis-applications-on-kubernetes-4gog?ref=daveabrock.com">autoscales Redis apps on Kubernetes</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-API-Access-With-API-Management/?ref=daveabrock.com">controls access to his API with Azure API Management</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/02/27/deferred-messages-in-azure-service-bus/?ref=daveabrock.com">defers messages with the Azure Service Bus</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/03/01/using-azure-ad-groups-authorization-in-asp-net-core-for-an-azure-blob-storage/?ref=daveabrock.com">uses Azure AD group authorization in ASP.NET Core for Azure Blob Storage</a>.</li><li>Ryan Palmer continues <a href="https://www.compositional-it.com/news-blog/safe-stack-authentication-with-active-directory-part-2/?ref=daveabrock.com">writing about SAFE authentication with Azure AD</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Prevent-Bugs-with-Static-Local-Functions?ref=daveabrock.com">works with static local functions in C#</a>.</li><li>Konrad Jokosa <a href="https://tooslowexception.com/the-8-most-missing-features-in-c/?ref=daveabrock.com">writes about the 8 most missing features in C#</a>.</li><li>Jesse Liberty <a href="http://jesseliberty.com/2021/03/02/c-coding-standards-updated/?ref=daveabrock.com">updates his C# coding standards</a>.</li><li>Kuba Ciechowski <a href="https://blog.ciechowski.net/using-collections-with-memberdata-attribute-in-f?ref=daveabrock.com">uses collections with the MemberData attribute in F#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Brian Douglas <a href="https://github.blog/2021-03-04-4-things-you-didnt-know-you-could-do-with-github-actions/?ref=daveabrock.com">writes about 4 things you can do with GitHub Actions</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/raw-sql-queries-with-ef-core-5?ref=daveabrock.com">writes raw SQL queries with EF Core 5</a>, and also <a href="https://khalidabuhakmeh.com/streaming-vs-buffered-results-with-entity-framework-core-5?ref=daveabrock.com">compares streamed results and buffered results with EF Core 5</a>.</li><li>Niels Swimberghe <a href="https://www.twilio.com/blog/better-twilio-authentication-csharp-twilio-api-keys?ref=daveabrock.com">writes about better Twilio authentication with Twilio API keys</a>.</li><li>Giorgi Dalakishvili <a href="https://www.giorgi.dev/miscellaneous/updating-linqpad-queryplanvisualizer-for-linqpad6-and-entity-framework-core/?ref=daveabrock.com">updates LINQPad.QueryPlanVisualizer for LINQPad6 and Entity Framework Core</a>.</li><li>Anne Gao <a href="https://devblogs.microsoft.com/visualstudio/intelligent-visual-studio-search-service?ref=daveabrock.com">writes about the Intelligent Visual Studio Search Service</a>.</li><li>James Newton-King <a href="https://devblogs.microsoft.com/aspnet/intellisense-for-appsettings-json?ref=daveabrock.com">writes about IntelliSense support for appsettings.json</a>.</li><li>Peter McKee <a href="https://www.docker.com/blog/how-to-use-your-own-registry-2/?ref=daveabrock.com">writes about how to use your own Docker registry</a>.</li><li>Nitya Narasimhan <a href="https://blog.dapr.io/posts/2021/03/02/a-visual-guide-to-dapr/?ref=daveabrock.com">introduces a visual guide to Dapr</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/02/azure-rest-apis-insomnia/?ref=daveabrock.com">uses the Azure REST APIs with Insomnia</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>ThoughtWorks writes about <a href="https://www.thoughtworks.com/insights/blog/mindset-shift-needed-kubernetes-adoption-part-1?ref=daveabrock.com">the required mindset shift for Kubernetes adoption</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/crossing-the-generics-divide/?ref=daveabrock.com">crosses the generics divide</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1729&ref=daveabrock.com">talks with Steve Gordon about Elasticsearch for .NET</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/243?ref=daveabrock.com">looks back on 3 years of FuGet</a>.</li><li>Software Engineering Radio <a href="https://www.se-radio.net/2021/02/episode-448-starting-your-own-software-company/?ref=daveabrock.com">talks about starting your own software company</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>JetBrains hosted <a href="https://blog.jetbrains.com/dotnet/2021/03/03/oss-power-ups-fluent-assertions-webinar-recording/?ref=daveabrock.com">a webinar with Dennis Doomen about Fluent Assertions</a>.</li><li>On .NET <a href="https://www.youtube.com/watch?v=R0ODfwU6MzQ&ref=daveabrock.com">dives deep into Microsoft Orleans</a> and also <a href="https://www.youtube.com/watch?v=f8Hf-YUrC10&ref=daveabrock.com">talks to Scott Addie about secretless .NET apps</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Ask About Azure: Why do resource groups need a location? ]]></title>
        <description><![CDATA[ In this post, we discuss why resource groups need to be bound to a location. ]]></description>
        <link>https://www.daveabrock.com/2021/03/08/ask-azure-resource-group-locations/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe94</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 07 Mar 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1501630834273-4b5604d2ee31?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNsb3VkfGVufDB8fHx8MTYxOTgyODkzNg&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Ask About Azure is a weekly-ish beginner-friendly series that answers common questions on Azure development and infrastructure topics.</em></p><p>In Azure, a <a href="https://docs.microsoft.com/azure/azure-resource-manager/management/manage-resource-groups-portal?ref=daveabrock.com#what-is-a-resource-group">resource group</a> is a logical container that you use to hold related resources. When you organize related resources together, it makes it easier to perform common operations on them. For example, you might have a resource group to host resources for a singular app like the web front end, APIs, and so on. You should deploy, monitor, update, and delete resources in a resource group together. Think of it as a family: you’ll have your ups and downs, but life is a lot easier when you do it together. (Mostly.)</p><p>A resource group is just a <em>logical container</em>, and the resources in your resource group can belong to various locations. The answer is pretty straightforward: you may want to have specific locations because of user requirements or maybe that certain Azure resources are only available in certain regions. The more interesting question is: if resource groups are logical and you can specify various locations for their resources, why do you need a specific location for your resource group?</p><p>If you try to create a resource group and leave out the location, you can’t create it.</p><p>If you create a resource group in the Azure Portal, you’ll see a required <code>Region</code> field:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/create-rg-portal.jpg" class="kg-image" alt="Create resource group in the portal" loading="lazy" width="1200" height="695" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/create-rg-portal.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/create-rg-portal.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/create-rg-portal.jpg 1200w" sizes="(min-width: 720px) 720px"></figure><p>If you go the scripting route, you’ll see it’s required in the <a href="https://docs.microsoft.com/azure/azure-resource-manager/management/manage-resource-groups-cli?ref=daveabrock.com#create-resource-groups">Azure CLI</a>:</p><pre><code>az group create --name MyResourceGroup --location centralus
</code></pre><p>In <a href="https://docs.microsoft.com/azure/azure-resource-manager/management/manage-resource-groups-powershell?ref=daveabrock.com#create-resource-groups">PowerShell</a>, it’s required as well:</p><pre><code>New-AzResourceGroup -Name MyResourceGroup -Location centralus
</code></pre><p>So why?</p><p>The resource group itself stores <em>metadata</em> about the resources inside it. If you’re a .NET developer, think of something like a Visual Studio solution (<em>.sln</em>) file: it has information about the project in the solution, the Visual Studio version you’re using, and so on. Instead of projects in a solution file, think of resources in a resource group.</p><p>Anyway, this metadata resides in the location you specified when you created the resource group. Your location is important when it comes to compliance. Your company or government may have specific rules, regulations, or laws about where you must store certain data. This metadata benefits <em>you</em>, too: it allows you to better manage your resources for cost management and security and access controls. For example, you can assign allocation tags to your resource group or orchestrate deployments for ARM templates. In terms of security, it’s common for teams to have their access scoped to a specific resource group to prevent impacting other resource groups with their changes. Information like this can reside in your resource group’s metadata.</p><p>How does availability play into this? If my resource group is in <code>Central US</code>, but my Azure Function app is in <code>East US 2</code>, an <code>East US 2</code> failure means the application won’t be available (unless you’ve made failure considerations, which you should). But what if <code>Central US</code> has an outage?</p><p>When this happens, your Function app in <code>East US 2</code> will still be online, but you won’t be able to deploy new resources until <code>Central US</code> goes online. As adding resources (or a “project”) definitely would force a change to the metadata, you won’t be able to do it when there’s an outage. Typically, updates to existing resources shouldn’t impact you. In these situations, you could wait until the outage clears. Alternately, create your resource in a new resource group, then move it to the existing resource group when the outage clears.</p><h1 id="references">References</h1><ul><li><a href="https://docs.microsoft.com/azure/azure-resource-manager/management/overview?ref=daveabrock.com">Azure Resource Manager overview</a> (Microsoft Docs)</li><li><a href="https://docs.microsoft.com/azure/azure-resource-manager/management/manage-resource-groups-portal?ref=daveabrock.com#what-is-a-resource-group">Manage resource groups</a> (Microsoft Docs)</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #39: 🔥 Is Dapr worth the hype? ]]></title>
        <description><![CDATA[ This week, is Dapr for real? ]]></description>
        <link>https://www.daveabrock.com/2021/03/06/dotnet-stacks-39/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe93</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 05 Mar 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-7.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Buckle up! It’s been a busy few weeks. With <a href="https://myignite.microsoft.com/?ref=daveabrock.com">Ignite this week</a>, things aren’t slowing down anytime soon. I’ve got you covered. Let’s get to it.</p><ul><li><strong>One big thing</strong>: Is Dapr worth the hype?</li><li><strong>The little things</strong>: Blazor Desktop, .NET 5 on Azure Functions, ASP.NET Core health checks</li><li>Last week in the .NET world</li></ul><h1 id="one-big-thing-is-dapr-worth-the-hype">One big thing: Is Dapr worth the hype?</h1><p>I mentioned Dapr <a href="https://daveabrock.com/2021/02/27/dotnet-stacks-38?ref=daveabrock.com">in passing last week</a>, but its release competed with <a href="https://daveabrock.com/2021/02/27/dotnet-stacks-38?ref=daveabrock.com#one-big-thing-net-6-gets-preview-1">the release of .NET 6 Preview 1</a>. I’ve been spending the last week trying to understand what exactly it is, and the <em>Dapr for .NET Developers</em> e-book <a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/?WT.mc_id=-blog-scottha&ref=daveabrock.com">has been mostly helpful</a>. With Ignite kicking off on Tuesday, you’re going to start hearing a lot more about it. (If you don’t work with microservices, feel free to scroll to the next section.)</p><p>Dapr is a runtime for your microservice environment—in .NET terms, you could call it a “BCL for the cloud.” It provides abstractions for you to work with the complexities of distributed applications. Dapr calls these pluggable components. Think about all the buckets your distributed systems have: authentication/authorization, pub/sub messaging, state management, invoking services, observability, secrets management, and so on. Your services can call these pluggable components directly, and Dapr deals with calling all these dependencies on your behalf. For example, to call Redis you call the Dapr state management API. You can call Dapr from its native REST or gRPC APIs and also language-specific SDKs. I <em>love</em> the idea of calling pub/sub over HTTP and not haggling with specific message broker implementations.</p><p>Dapr uses a sidecar architecture, enabling it to run in a separate memory process. Dapr says this provides isolation—Dapr can connect to a service but isn’t dependent on it. Each service can then have its own runtime environment. It can run in your existing environment, the edge, and Kubernetes (it’s built for containerized environments). While shepherded for Microsoft, it’s pretty agnostic and isn’t only built for Azure (but that might be lost in the Microsoft messaging). With Dapr, services communicate through encrypted channels, service calls are automatically retried when transient errors occur, and automatic service discovery reduces the amount of configuration needed for services to find each other.</p><p>While Dapr is service mesh-<em>like</em>, it is more concerned with handling distributed application features and is not dedicated network infrastructure. Yes, Dapr is a proxy. But if you’re in the cloud, breaking news: you’re using proxies whether you like it or not.</p><p>Dapr promises to handle the tricky parts for you through a consistent interface. Sure, you can do retries, proxies, network communication, and pub/sub on your own, but it’s probably a lot of duct tape and glue if you have a reasonably complex system.</p><p>With the <a href="https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/?ref=daveabrock.com">release of Dapr v1.0</a>, it’s production-ready. Will this latest “distributed systems made easy” offering solve all your problems? Of course not. Dapr uses the calls over the highly-performant gRPC, but <a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/dapr-at-20000-feet?ref=daveabrock.com#dapr-performance-considerations">that’s a lot of network calls</a>. The line <em>To increase performance, developers can call the Dapr building blocks with gRPC</em> needs some unpacking. The team discusses low latency but will REST be enough for all its chatter? Are you ready to hand your keys to yet another layer of abstraction? Would you be happy with a cloud within your cloud? Does your app have scale and complexity requirements that make this a necessity? Are you worried about leaky abstractions?</p><p>There’s a lot going on here, and I plan to explore more. If you wanted to learn more about Dapr, I hope this gets the ball rolling for you.</p><hr><h1 id="the-little-things-blazor-desktop-net-5-on-azure-functions-health-checks">The little things: Blazor Desktop, .NET 5 on Azure Functions, health checks</h1><p>With the release of <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/?ref=daveabrock.com">.NET 6 Preview 1 last week</a>, one of the most interesting takeaways was the mention of Blazor desktop apps. (It wasn’t part of Preview 1, but a preview of what’s to come for .NET 6.) As if we didn’t have enough desktop dev options to worry about—WPF, UWP, WinUI, .NET MAUI, WinForms, and so on–where does this even fit?</p><p>Here’s <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/?ref=daveabrock.com#blazor-desktop-apps">what Richard Lander wrote</a>:</p><blockquote>Blazor has become a very popular way to write .NET web apps. We first supported Blazor on the server, then in the browser with WebAssembly, and now we’re extending it again, to enable you to write Blazor desktop apps. Blazor desktop enables you to create hybrid client apps, which combine web and native UI together in a native client application. It is primarily targeted at web developers that want provide rich client and offline experiences for their users.</blockquote><p>Initially, Blazor Desktop will not utilize WebAssembly. Built on top of the .NET MAUI platform coming with .NET 6, it’ll use that stack to use native containers and controls. You can choose to use Blazor for your entire desktop app or only for targeted functionality—in the blog post, Lander mentions a Blazor-driven user profile page integrated with an otherwise native WPF app.</p><p>It appears this will work similarly to Electron. There will be a WebView control responsible for rendering content from an embedded Blazor web server, which can serve both Blazor components and other static assets. If you’re hoping to see one unifying platform for native development, I wouldn’t hold your breath—but if you like working with Blazor (especially if you’re apprehensive of XAML), it’ll be worth a try.</p><hr><p>In this week’s shameless plug, I <a href="https://daveabrock.com/2021/02/24/functions-dotnet-5?ref=daveabrock.com">wrote about using Azure Functions with .NET 5</a>. A new out-of-process model is in preview. Here’s the story behind it:</p><blockquote>Traditionally, .NET support on Azure Functions has been tied to the Azure Functions runtime. You couldn’t just expect to use the new .NET version in your Functions as soon as it was released. Because .NET 5 is not LTS, and Microsoft needs to support specific releases for extended periods, they can’t upgrade the host to a non-LTS version because it isn’t supported for very long (15 months from the November 2020 release). This doesn’t mean you can’t use .NET 5 with your Azure Functions. To do so, the team has rolled out a new out-of-process model that runs a worker process along the runtime. Because it runs in a separate process, you don’t have to worry about runtime and host dependencies. Looking long-term: it provides the ability to run the latest available version of .NET without waiting for a Functions upgrade.</blockquote><p>As its in early preview, it does take some work to get going with it, but ultimately it’s great news for getting Azure Functions to support new .NET releases much sooner.</p><hr><p>At work, we had a hackathon of sorts to build an authentication API to validate Azure runbooks, and roll it out to production in two weeks (a <em>mostly</em> fun exercise). I hadn’t built out an ASP.NET Core Web API from scratch in awhile, and <a href="https://docs.microsoft.com/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0&ref=daveabrock.com">implemented health checks</a>.</p><p>Of course, I knew you could add an endpoint in your middleware for a simple check:</p><pre><code class="language-csharp">public void Configure(IApplicationBuilder app)
{
    app.UseRouting();
    app.UseEndpoints(endpoints =&gt;
    {
        endpoints.MapHealthChecks("/api/healthcheck");
    });
}
</code></pre><p>There’s a <a href="https://docs.microsoft.com/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0&ref=daveabrock.com#health-check-options">ton of configuration options</a> at your disposal, and after reading Kevin Griffin’s <a href="https://consultwithgriff.com/monitoring-aspnet-core-application-health-with-health-checks/?ref=daveabrock.com">timely blog post</a>, I learned about the <code>AspNetCore.Diagnostics.HealthChecks</code> library. Did you <a href="https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks?ref=daveabrock.com">know about this</a>? Where have I been? You can plug into health check packages for widely used services like Kubernetes, Redis, Postgres, and more. There’s even a <a href="https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks?ref=daveabrock.com#HealthCheckUI">UI you can leverage</a>. In case you weren’t aware—maybe you were—I hope you find it helpful.</p><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-4">🔥 The Top 4</h2><ul><li>Andrew Lock <a href="https://andrewlock.net/using-source-generators-with-a-custom-attribute--to-generate-a-nav-component-in-a-blazor-app/?ref=daveabrock.com">uses source generators with a custom attribute to generate a menu component in a Blazor app</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2021/02/24/entity-framework-core-5-pitfalls-to-avoid-and-ideas-to-try/?ref=daveabrock.com">writes about EF Core 5 pitfalls and ideas</a>.</li><li>Jon Galloway <a href="https://devblogs.microsoft.com/aspnet/generating-http-api-clients-using-visual-studio-connected-services?ref=daveabrock.com">generates API clients using Visual Studio Connected Services</a>.</li><li>Brady Gaster <a href="https://devblogs.microsoft.com/aspnet/app-building-with-azure-api-management-functions-power-apps-and-logic-apps?ref=daveabrock.com">builds apps with Azure API Management, Functions, Power Apps, and Logic Apps</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>The nuget.org repository <a href="https://devblogs.microsoft.com/nuget/the-nuget-org-repository-signing-certificate-will-be-updated-as-soon-as-march-15th-2021?ref=daveabrock.com">signing certificate will be updated as soon as March 15</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/opentelemetry-1-0-extensions-released/?ref=daveabrock.com">releases the extensions for OpenTelemetry 1.0</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Microsoft Ignite <a href="https://myignite.microsoft.com/home?ref=daveabrock.com">starts on Tuesday</a>.</li><li>Check out the <a href="https://www.youtube.com/watch?v=mZRNjixZEMg&ref=daveabrock.com">entire stream</a> of this week’s .NET Conf (“Focus on Windows”).</li><li>The .NET Docs Show talks to <a href="https://www.youtube.com/watch?v=qY2u1mWgt_I&ref=daveabrock.com">Mika Dumont about Roslyn analyzers</a>.</li><li>For standups this week, ASP.NET <a href="https://www.youtube.com/watch?v=Mpf0fCO6NrU&ref=daveabrock.com">talks about building HTTP APIs</a> and EF <a href="https://www.youtube.com/watch?v=VgNFFEqwZPU&ref=daveabrock.com">talks about performance tuning</a>.</li><li>The .NET team <a href="https://devblogs.microsoft.com/dotnet/survey-library-open-source?ref=daveabrock.com">wants you to fill out a “State of .NET” survey</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/02/24/blog/posts/net-foundation-january-february-2021-update?ref=daveabrock.com">provides a January/February 2021 update</a>.</li><li>Uno Platform <a href="https://platform.uno/blog/uno-platform-sponsors-net-foundation/?ref=daveabrock.com">is sponsoring the .NET Foundation</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2021/02/19/blog/posts/announcing-the-dot-net-foundation-speakers-directory?ref=daveabrock.com">rolls out a speakers directory</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>The Uno Platform <a href="https://platform.uno/blog/migrating-silverlight-apps-to-winui-uno-platform-xaml-in-the-browser/?ref=daveabrock.com">migrates Silverlight apps to WinUI + Uno Platform</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/how-to-implement-dependency-injection-in-asp-net-core?ref=daveabrock.com">writes about implementing dependency injection in ASP.NET Core</a>.</li><li>Kevin W. Griffin <a href="https://consultwithgriff.com/monitoring-aspnet-core-application-health-with-health-checks/?ref=daveabrock.com">monitors ASP.NET Core applications with health checks</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-streams-with-httpclient-to-improve-performance-and-memory-usage/?ref=daveabrock.com">uses streams with HttpClient to improve performance</a>, and also <a href="https://code-maze.com/using-httpclient-to-send-http-patch-requests-in-asp-net-core/?ref=daveabrock.com">uses HttpClient to send HTTP PATCH requests in ASP.NET Core</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/blazor-desktop-the-electron-for-net-ecdcf5c30027?ref=daveabrock.com">writes about Blazor Desktop</a>, and <a href="https://visualstudiomagazine.com/articles/2021/02/25/app-model.aspx?ref=daveabrock.com">so does David Ramel</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/how-to-implement-two-factor-authentication-with-asp-net-core/?ref=daveabrock.com">implements two-factor implementation in ASP.NET Core</a>.</li><li>Camilo Reyes <a href="https://www.red-gate.com/simple-talk/dotnet/net-tools/integrate-create-react-app-with-net-core-5/?ref=daveabrock.com">integrates the Create React app with .NET 5</a>.</li><li>Matt Watson <a href="https://stackify.com/asp-net-performance-tools-you-need-to-know/?ref=daveabrock.com">shows off how to monitor performance in ASP.NET</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/620/building-and-auto-deploying-an-aspnet-core-application-part-3-dealing-with-change?ref=daveabrock.com">continues building and auto-deploying an ASP.NET Core app</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-aws-amplify?ref=daveabrock.com">deploys Blazor WebAssembly to AWS Amplify</a> and <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-heroku?ref=daveabrock.com">also Heroku</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Szymon Kulec <a href="https://blog.scooletz.com/2021/02/23/performance-investigations?ref=daveabrock.com">writes about .NET performance investigations</a>.</li><li>Hannes Du Preez <a href="https://www.developer.com/net/net/microsoft-win32-apis-become-more-.net-compatible.html?ref=daveabrock.com">writes about how Microsoft Win32 APIs have become more .NET compatible</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/aspnet-core-dependency-injection-what-is-the-iserviceprovider-and-how-is-it-built?ref=daveabrock.com">writes about DI and the IServiceProvider</a>.</li><li>Bruno Capuano <a href="https://elbruno.com/2021/02/24/net6-single-file-apps-improved-for-windows-and-mac/?ref=daveabrock.com">configures a single-file app in .NET 6</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/windows-developer-roadmap/?ref=daveabrock.com">builds a roadmap for Windows development</a>.</li><li>Mark Heath <a href="https://markheath.net/post/porting-interop-and-webassembly?ref=daveabrock.com">writes about porting versus interop for .NET</a>.</li><li>Joe Mayo <a href="https://joemayo.medium.com/getting-net-6-8776d03798ec?ref=daveabrock.com">writes about getting .NET 6 (for Mac)</a>.</li><li>Elton Stoneman <a href="https://blog.sixeyed.com/experimenting-with-net-5-and-6-using-docker-containers/?ref=daveabrock.com">experiments with .NET 5 and 6 using Docker containers</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Thiago Custódio <a href="https://www.infoq.com/news/2021/02/richter-azure-net-sdk/?ref=daveabrock.com">talks with Jeffrey Richter about the Azure .NET SDKs</a>.</li><li>Brandon Minnick <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/preview-creating-azure-functions-using-net-5/ba-p/2156846?ref=daveabrock.com">creates Azure Functions with .NET 5</a>, and <a href="https://daveabrock.com/2021/02/24/functions-dotnet-5?ref=daveabrock.com">so does Dave Brock</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-Azure-Functions-Integration-With-Microsoft-Graph/?ref=daveabrock.com">integrates his app with the Graph SDK and Azure AD B2C</a>.</li><li>Gregor Suttie <a href="https://gregorsuttie.com/2021/02/22/troubleshooting-app-services-in-azure/?ref=daveabrock.com">troubleshoots App Services in Azure</a>.</li><li>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/build-and-deploy-to-azure-static-web-apps-with-stackbit/ba-p/2116687?ref=daveabrock.com">builds and deploys to Azure Static Web Apps with Stackbit</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Yacoub Massad <a href="https://www.dotnetcurry.com/fsharp/fsharp-features-part-1?ref=daveabrock.com">works through F# language features using a Toc-Tac-Toe example</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/02/25/c-9-0-pattern-matching-in-switch-expressions/?ref=daveabrock.com">writes about switch expression pattern matching in C# 9</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Simplify-Array-Access-and-Range-Code?ref=daveabrock.com">simplifies array access and range code in C#</a>.</li><li>Nikos Vaggalis <a href="https://www.i-programmer.info/news/231-methodology/14358-design-patterns-explained-with-food-in-c.html?ref=daveabrock.com">explains design patterns in C# with food</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/02/23/static-refactoring-with-visual-studio-regular-expressions/?ref=daveabrock.com">works on static refactoring with Visual Studio regular expressions</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/five-levels-of-performance-tuning-for-an-ef-core-query/?ref=daveabrock.com">offers five levels of performance tuning for an EF Core query</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/02/22/dapr1.aspx?ref=daveabrock.com">writes about Dapr</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/entity-framework-core-5-value-converters?ref=daveabrock.com">writes about EF Core 5 value converters</a>.</li><li>Jason Gaylord <a href="https://www.jasongaylord.com/blog/2021/02/25/add-expression-in-azure-devops-variable?ref=daveabrock.com">adds a pipeline expression value to an Azure DevOps variable</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/install-tailwind-css-with-aspnet-core?ref=daveabrock.com">installs Tailwind CSS with ASP.NET Core</a>.</li><li>The Edge team <a href="https://blogs.windows.com/msedgedev/2021/02/23/six-time-saving-tips-edge-devtools-console?ref=daveabrock.com">writes about six time-saving tips when using the DevTools Console</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Gerald Versluis <a href="https://devblogs.microsoft.com/xamarin/xamarin-community-toolkit-tabview?ref=daveabrock.com">writes about building beautiful tabs with the Xamarin Community Toolkit</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/how-to-use-push-notifications-xamarin-forms?ref=daveabrock.com">uses push notifications in Xamarin Forms</a>, and also  <a href="https://askxammy.com/replicating-food-delivery-ui-in-xamarin-forms/?ref=daveabrock.com">replicates a food delivery UI</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-057-open-source-mediatr-and-automapper-with-jimmy-bogard/?ref=daveabrock.com">talks with Jimmy Bogard</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-184-cloud-native-with-facundo-and-faheem/?ref=daveabrock.com">talks to Faheem Memon and Facundo Gauna about going cloud-native</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1728&ref=daveabrock.com">talks to Mark Rendle about migrating WCF</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=hHLZqBXuIZE&ref=daveabrock.com">avoid SSL expirations</a>.</li><li>The ON .NET Show talks <a href="https://www.youtube.com/watch?v=kIfmwmJHNMs&ref=daveabrock.com">about Dapr with Ryan Nowak</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #38: 📢 I hope you like announcements ]]></title>
        <description><![CDATA[ This week, both .NET 6 Preview 1 and Dapr v1.0 are released. ]]></description>
        <link>https://www.daveabrock.com/2021/02/27/dotnet-stacks-38/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe91</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 26 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-8.png" medium="image"/>
        <content:encoded><![CDATA[ <p>It was very busy last week! Let’s get right to it.</p><ul><li>One big thing: .NET 6 gets Preview 1</li><li>The little things: Dapr v1.0 is released, Azure Static Web Apps, more SolarWinds findings</li><li>Dev Discussions: Cecil Phillip</li><li>Last week in the .NET world</li></ul><h1 id="one-big-thing-net-6-gets-preview-1">One big thing: .NET 6 gets Preview 1</h1><p>It seems like just yesterday .NET 5 went live. (It was November, for the record.) This week, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/?ref=daveabrock.com">the .NET team announced</a> .NET 6 Preview 1, to be officially released in November 2021. You can also check out the <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-1/?ref=daveabrock.com">ASP.NET Core</a> and <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/?ref=daveabrock.com">EF Core 6</a> announcements. .NET 6 will be <a href="https://github.com/dotnet/core/blob/master/release-policies.md?ref=daveabrock.com">an enterprise-friendly LTS release</a>, meaning it will be supported for three years.</p><p>As expected, a main focus will be integrating Xamarin into the “One .NET” model by way of the <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/?ref=daveabrock.com#net-multi-platform-app-ui">.NET Multi-Platform App UI (MAUI)</a>. With Preview 1, Xamarin developers can develop Android and iOS with MAUI. Future previews will address support for macOS and Windows. Another big goal is improving the inner loop experience. You can <a href="https://themesof.net/?ref=daveabrock.com">check out <em>themesof.net</em></a> to see what’s being prioritized. AOT support is not rolled out yet, but you can <a href="https://github.com/dotnet/runtimelab/tree/feature/NativeAOT?ref=daveabrock.com">head over to the NativeAOT repo</a> to get up to speed.</p><p>For ASP.NET Core 6, they’re prioritizing work on <a href="https://github.com/dotnet/aspnetcore/issues/18486?ref=daveabrock.com">hot reload</a>, <a href="https://github.com/dotnet/aspnetcore/issues/27724?ref=daveabrock.com">micro APIs</a>, <a href="https://github.com/dotnet/aspnetcore/issues/5466?ref=daveabrock.com">AoT compilation</a>, <a href="https://github.com/dotnet/aspnetcore/issues/27887?ref=daveabrock.com">updated SPA support</a>, and <a href="https://github.com/dotnet/aspnetcore/issues/15271?ref=daveabrock.com">HTTP/3</a>. For Preview 1, the team now supports <code>IAsyncDisposable</code> in MVC, offers a new <code>DynamicComponent</code> for Blazor to render a component based on type, and applying more nullability annotations.</p><p>For EF Core 6, the team is busy with <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/?ref=daveabrock.com#support-for-sql-server-sparse-columns">support for SQL Server sparse columns</a>, required property validations for <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/?ref=daveabrock.com#support-for-sql-server-sparse-columns">not null for the in-memory database</a>, improved SQL Server translation for <code>IsNullOrWhitespace</code>, a <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/?ref=daveabrock.com#savepoints-api">Savepoints API</a>, and much more.</p><p>It’s sure to be a busy eight months. Stay tuned.</p><h1 id="the-little-things-dapr-v1-0-is-released-azure-static-web-apps-more-solarwinds-findings">The little things: Dapr v1.0 is released, Azure Static Web Apps, more SolarWinds findings</h1><p>This week, Dapr <a href="https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/?ref=daveabrock.com">hit GA with v1.0</a>. The next in a long line of technologies that promise to make distributed systems easier, we’ll see if this one sticks. While it’s hard for folks to pin down what exactly Dapr is—<a href="https://news.ycombinator.com/item?id=26173566&ref=daveabrock.com">no, seriously</a>—it uses pluggable components to remove the complexity of low-level plumbing involved with developing distributed applications.</p><p>Here’s more detail from the new <a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/?ref=daveabrock.com"><em>Dapr for .NET Developers</em> e-book</a>:</p><blockquote>It provides a dynamic glue that binds your application with infrastructure capabilities from the Dapr runtime. For example, your application may require a state store. You could write custom code to target Redis Cache and inject it into your service at runtime. However, Dapr simplifies your experience by providing a distributed cache capability out-of-the-box. Your service invokes a Dapr building block that dynamically binds to Redis Cache component via a Dapr configuration. With this model, your service delegates the call to Dapr, which calls Redis on your behalf. Your service has no SDK, library, or direct reference to Redis. You code against the common Dapr state management API, not the Redis Cache API.</blockquote><p>–</p><p>In my <a href="https://www.meetup.com/Bournemouth-ASP-NET-Blazor-Meetup-Group/events/275962302/?ref=daveabrock.com">talk last week</a> on Azure Static Web Apps, it was nice to see Anthony Chu attend. He’s the PM for Azure Functions and Azure Static Web Apps. We asked what’s new with Azure Static Web Apps—he talked about a new tier, a CLI for a better local development experience, root domain support (right now it supports custom DNS with <em>https://mysite.com</em> but not <em>https://www.mysite.com</em>), an SLA, and more. There’s no firm dates on these things, but it looks like improvements are on the way before Microsoft takes it out of preview.</p><p>–</p><p>We heard a little more about how the SolarWinds hack <a href="https://www.reuters.com/article/idUSL1N2KO3ME?ref=daveabrock.com">hit Microsoft</a>:</p><blockquote>Microsoft said its internal investigation had found the hackers studied parts of the source code instructions for its Azure cloud programs related to identity and security, its Exchange email programs, and Intune management for mobile devices and applications. Some of the code was downloaded, the company said, which would have allowed the hackers even more freedom to hunt for security vulnerabilities, create copies with new flaws, or examine the logic for ways to exploit customer installations … Microsoft had said before that the hackers had accessed some source code, but had not said which parts, or that any had been copied.</blockquote><p>Microsoft <a href="https://msrc-blog.microsoft.com/2021/02/18/microsoft-internal-solorigate-investigation-final-update/?ref=daveabrock.com">blogged</a> their “final update,” so that’s all we’ll hear about it. It looks like their defenses held up.</p><h2 id="dev-discussions-cecil-phillip">Dev Discussions: Cecil Phillip</h2><p>I recently had a chance to catch up with Cecil Phillip, a Senior Cloud Advocate for Microsoft. He’s a busy guy: you might have seen him co-hosting <a href="https://dotnet.microsoft.com/live/dotnet-docs?ref=daveabrock.com">The .NET Docs Show</a> or the <a href="https://channel9.msdn.com/Shows/On-NET?ref=daveabrock.com">ON.NET Show</a>. Cecil also does a lot with with microservices and distributed systems. I wanted to pick his brain on topics like Dapr, YARP, and Service Fabric. I hope you enjoy it.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/cecil-phillip-1.png" class="kg-image" alt="Cecil Phillip profile photo" loading="lazy" width="250" height="250"></figure><blockquote>I’d love to hear about how you got in this field and ended up at Microsoft.</blockquote><p>I’ll try to give you a condensed version. Back in Antigua, we didn’t have computers in school at the time. One day, my dad brought home a <a href="https://en.wikipedia.org/wiki/Compaq_Presario?ref=daveabrock.com">Compaq Presario</a> to upgrade from using a typewriter that he used for working on his reports. Initially, I wasn’t allowed to “experiment” with the machine, so I’d explore it when he wasn’t around. I was so curious about what this machine could do, I wanted to know what every button did—and eventually, I got better at it than he was.</p><p>I went to college and got my CS degrees. I didn’t know I wanted to be a programmer. I didn’t know many examples of what CS folks did at the time. I got my first job working on ASP.NET Web Forms applications. After I got my green card, I spent a few years exploring different industries like HR, Finance, and Education. I taught some university courses in the evenings, and it was at that point I realized how much I loved teaching kids. Then one day, I saw a tweet about a new team at Microsoft, and I thought, “Why not?” I didn’t think I’d get the job, but I’d give it a try.</p><blockquote>When it comes to microservices, there’s been a lot of talk about promoting the idea of “loosely coupled monoliths” when the overhead of microservices might not be worth it. What are your thoughts?</blockquote><p>Somewhere along the way, having your application get labeled as a monolith became a negative thing. In my opinion, we’ve learned a lot of interesting patterns that we can apply to both monoliths and microservices. For some solutions and teams, having a monolith is the right option. We can now pair that with the additional benefits of modern patterns to get some additional resiliency for a stable application.</p><blockquote>I’ve been reading and learning about YARP, a .NET reverse proxy. Why would I use this over something like nginx?</blockquote><p>If you’re a .NET developer and want the ability to write custom rules or extensions for your reverse proxy/load balancer using your .NET expertise, then <a href="https://microsoft.github.io/reverse-proxy/articles/getting_started.html?ref=daveabrock.com">YARP</a> is a great tool.</p><blockquote>Azure Front Door seems reverse-proxy<em>ish</em>—why should I choose YARP over this?</blockquote><p><a href="https://azure.microsoft.com/services/frontdoor/?ref=daveabrock.com">Azure Front Door</a> is a great option if you’re running large-scale applications across multiple regions. It’s a hosted service with load balancing features, so you get things like SSL management, layer-7 routing, health checks, URL rewriting, and so on. YARP, on the other hand, is middleware for ASP.NET Core that implements some of those same reverse proxy concerns, but you’re responsible for your infrastructure and have to write code to enable your features. YARP would be more akin to something like <a href="http://www.haproxy.org/?ref=daveabrock.com">HAProxy</a> or <a href="https://nginx.org/en/?ref=daveabrock.com">nginx</a>.</p><blockquote>A lot of enterprises, like mine, use nginx for an AKS ingress controller. Will YARP ever help with something like that?</blockquote><p>Maybe. 🙂</p><blockquote>I know you’ve also been working with Dapr. I know it simplifies event management for microservices, but can you illustrate how it can help .NET developers and what pain points it solves?</blockquote><p>The biggest selling point for <a href="https://dapr.io/?ref=daveabrock.com">Dapr</a> is that it provides an abstraction over common needs for microservice developers. In the ecosystem today, there are tons of options to choose from to get a particular thing done— but with that comes tool-specific SDKs, APIs, and configuration. Dapr allows you to choose the combination of tools you want without needing to have your code rely on tool-specific SDKs. That includes things like messaging, secrets, service discovery, observability, actors, and so on.</p><blockquote>How does Dapr compare with something like Service Fabric? Is there overlap, and do you see Dapr someday replacing it?</blockquote><p>I look at Dapr and <a href="https://azure.microsoft.com/en-us/services/service-fabric/?ref=daveabrock.com">Service Fabric</a> as two completely different things. Dapr is an open-source, cross-platform CLI tool that provides building blocks for making microservice development easier. Service Fabric is a hosted Azure service that helps with packaging and deploying distributed applications. Dapr can run practically anywhere—on any cloud, on-premises, and Kubernetes. You can even run it on Service Fabric clusters since Service Fabric can run processes. It can run containers and even contains a programming model that applications can use as a hard dependency. Dapr itself is a process that would run beside your application’s various instances to provide some communication abstractions.</p><blockquote>What is your one piece of programming advice?</blockquote><p>I think it’s important to spent time reading code. We should actually read more code than we write. There’s so we can learn and be inspired by exploring the techniques used by the developers that have come before us.</p><p><em>You can connect with Cecil Phillip <a href="https://twitter.com/cecilphillip?ref=daveabrock.com">on Twitter</a>.</em></p><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/use-project-tye-to-host-blazor-wasm-and-aspdotnet-web-api-on-a-single-origin?ref=daveabrock.com">uses Project Tye to host Blazor WASM and ASP.NET Web API on a single origin to avoid CORS</a> and also <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-aws-amplify?ref=daveabrock.com">deploys Blazor WebAssembly to AWS Amplify</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/using-source-generators-to-generate-a-nav-component-in-a-blazor-app/?ref=daveabrock.com">uses source generators to generate a menu component in a Blazor app</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/aspnet-core-dependency-injection-what-is-the-iservicecollection?ref=daveabrock.com">writes about the IServiceCollection and dependency injection</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>.NET 6 preview 1 is out: Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1?ref=daveabrock.com">has the main announcement</a>, Sourabh Shirhatti <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-1?ref=daveabrock.com">talks about ASP.NET Core updates</a>, and Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1?ref=daveabrock.com">announces what’s new with EF Core 6</a></li><li>Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-february-2021-cumulative-update-preview-for-net-framework?ref=daveabrock.com">releases the .NET Framework monthly cumulative update</a>.</li><li>The Azure SDK folks <a href="https://devblogs.microsoft.com/azure-sdk/february-release-2021?ref=daveabrock.com">provide their monthly update</a>.</li><li>Dapr v1.0 <a href="https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/?ref=daveabrock.com">released this week</a>, and the Dapr folks <a href="https://cloudblogs.microsoft.com/opensource/2021/02/17/the-community-effort-that-delivered-dapr-v1-0?ref=daveabrock.com">talk about the community effort to deliver Dapr v1.0</a>. (.NET 6 Preview 1 stole the show this week, and I’ll address this in detail next week.)</li><li>GitHub Enterprise Server 3.0 <a href="https://github.blog/2021-02-16-github-enterprise-server-3-0-is-now-generally-available/?ref=daveabrock.com">is generally available</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Chris Sainty <a href="https://chrissainty.com/blazored-hits-1-000-000-downloads-on-nuget/?ref=daveabrock.com">hits a million Blazored downloads</a>.</li><li>For standups this week: .NET Tooling talks … <a href="https://www.youtube.com/watch?v=sGkW9AkuJag&ref=daveabrock.com">tools</a>, Machine Learning <a href="https://www.youtube.com/watch?v=Vmgv_HJmJkE&ref=daveabrock.com">looks at ML.NET APIs</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=xoYkk5jk8d0&ref=daveabrock.com">discusses flexible HTTP APIs</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=IGJY2FW-gy0&ref=daveabrock.com">talks with Daniel Krzyczkowski</a> about the Microsoft Identity Platform, but I really wonder: does he work inside of a GitHub contribution graph?</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>David Jones <a href="https://davidjones.sportronics.com.au/blazor/Blazor_Helpers_App-More_on_Includes_with_Selections-blazor.html?ref=daveabrock.com">writes about using .Includes in EF with a Blazor Server app</a>.</li><li>Josef Ottosson <a href="https://josef.codes/my-take-on-the-result-class-in-c-sharp/?ref=daveabrock.com">offers his thoughts on the Result class</a>.</li><li>Sam Basu <a href="https://www.telerik.com/blogs/blazor-on-desktop?ref=daveabrock.com">writes about how to make Blazor web apps for Desktop</a>.</li><li>Dave Brock (hi!) <a href="https://daveabrock.com/2021/02/18/copy-to-clipboard-markdown-editor?ref=daveabrock.com">builds a Blazor ‘Copy to Clipboard’ component</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/02/19/require-user-password-verification-with-asp-net-core-identity-to-access-razor-page/?ref=daveabrock.com">works on requiring user password verification with ASP.NET Core identity to access Razor Pages</a>.</li><li>Shawn Wildermuth <a href="http://wildermuth.com/2021/02/15/I-Was-Wrong---Hosting-SPAs-in-ASP-NET-Core?ref=daveabrock.com">offers a mea culpa on hosting SPAs in ASP.NET Core</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/blash-twitter-dashboard-net-5-app-source-code-twitter-api?ref=daveabrock.com">continues work on his Twitter dashboard .NET 5 app</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/fetching-data-with-httpclient-in-aspnetcore/?ref=daveabrock.com">works on fetching data and content negotiation with HttpClient in ASP.NET Core</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/fix-dotnet-dependencies-with-monkey-patching?ref=daveabrock.com">fixes .NET dependencies with monkey patching</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/android-net-6/?ref=daveabrock.com">builds an Android app with .NET 6</a>.</li><li>Mitchel Sellers <a href="https://www.mitchelsellers.com/blog/article/net-5-deterministic-builds-source-linking?ref=daveabrock.com">writes about deterministic builds and source linking in .NET 5</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Justin Yoo <a href="https://dev.to/azure/keyvault-secrets-rotation-management-in-bulk-5fl1?ref=daveabrock.com">writes about bulk managing Key Vault secret rotation</a>.</li><li>Tim Sander <a href="https://devblogs.microsoft.com/cosmosdb/new-ways-to-use-composite-indexes?ref=daveabrock.com">writes about new ways to use composite indexes in Azure Cosmos DB</a>.</li><li>Gregor Suttie <a href="https://gregorsuttie.com/2021/02/15/azure-durable-functions-support-caller/?ref=daveabrock.com">uses Azure Durable Functions to place phone calls when alerts trigger</a>.</li><li>Adam Storr <a href="https://adamstorr.azurewebsites.net/blog/controlling-the-logging-levels-in-azure-functions?ref=daveabrock.com">controls logging levels in Azure Functions</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/02/16/adding-asp-net-core-authorization-for-an-azure-blob-storage-and-azure-ad-users-using-role-assignments/?ref=daveabrock.com">adds ASP.NET Core authorization for an Azure Blob Storage and Azure AD users for role assignments</a>.</li><li>Dominique St-Amand <a href="https://www.domstamand.com/common-azure-functions-in-csharp-quick-faqs-and-tips/?ref=daveabrock.com">has some FAQs and tips for Azure Functions in C#</a>.</li><li>Brandon Minnick <a href="https://codetraveler.io/2021/02/12/creating-azure-functions-using-net-5/?ref=daveabrock.com">creates Azure Functions using .NET 5</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/02/18/c-9-0-improved-pattern-matching/?ref=daveabrock.com">writes about improved pattern matching with C# 9</a>.</li><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/02/13/returning-more-than-one-result-from-a-method-tuple/?ref=daveabrock.com">writes about C# tuples</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Nested-Switch-Expressions?ref=daveabrock.com">works on C# nested switch expressions</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/playing-the-super-mario-bros-theme-with-csharp?ref=daveabrock.com">plays the Super Mario Bros. theme with C#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/dotnet-boxed-includes-prescriptive-templates-for-net-core?ref=daveabrock.com">writes about DotNet Boxed for prescriptive templates for .NET Core</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/winui-3-0-debugging-tooling-with-visual-studio/?ref=daveabrock.com">works on WinUI 3 debugging tooling with Visual Studio</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/export-data-from-google-analytics-with-net/?ref=daveabrock.com">exports data from Google Analytics with .NET</a>.</li><li>Jonathan Bowman <a href="https://dev.to/bowmanjd/install-docker-on-windows-wsl-without-docker-desktop-34m9?ref=daveabrock.com">installs Docker on WSL without Docker Desktop</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Mohammed Ismail Sameer Mohamed Saleem <a href="https://www.syncfusion.com/blogs/post/10-tips-to-avoid-common-mistakes-in-xamarin-forms-app-development.aspx?ref=daveabrock.com">helps you avoid common mistakes in Xamarin development</a>.</li><li>Luis Matos <a href="https://luismts.com/style-library-xamarin-forms/?ref=daveabrock.com">creates a scalable style library in Xamarin Forms</a>.</li><li>Denys Fiediaiev <a href="https://prin53.medium.com/pop-up-validation-in-xamarin-with-mvvmcross-b035f0193ba4?ref=daveabrock.com">works on pop-up validation in Xamarin with MvvmCross</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/applying-simple-navigation-xamarin-forms?ref=daveabrock.com">adds simple navigation in Xamarin Forms</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Derek Comartin <a href="https://codeopinion.com/event-sourcing-example-explained-in-plain-english/?ref=daveabrock.com">explains event sourcing</a>.</li><li>Steve Smith <a href="https://ardalis.com/dto-or-poco/?ref=daveabrock.com">compares DTOs and POCOs</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-70-picking-the-right-azure-resources-with-barry-luijbregts/?ref=daveabrock.com">talks to Barry Luijbregts about picking the right Azure resources</a>.</li><li>Serverless Chats <a href="https://www.serverlesschats.com/88/?ref=daveabrock.com">talk to Jeff Hollan about Azure Functions</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-056-how-does-hotchocolate-and-strawberryshake-relate-to-net-and-graphql/?ref=daveabrock.com">discusses HotChocolate and StrawberryShake</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-183-developer-velocity-with-amanda-silver/?ref=daveabrock.com">discusses developer velocity with Amanda Silver</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/How-Azure-SQL-Enables-Real-time-Operational-Analytics-HTAP-Part-1?ref=daveabrock.com">talks about how Azure SQL enables real-time analytics</a>.</li><li>Leslie Richardson <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/NET-Conf-Focus-on-Windows?ref=daveabrock.com">talks to Beth Massi about the upcoming .NET Conf</a>.</li><li>AzureFunBytes <a href="https://devblogs.microsoft.com/devops/azurefunbytes-dapr-on-azure?ref=daveabrock.com">introduces Dapr on Azure</a>.</li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/Xamarin-Community-Toolkit-MultiConverter--VariableMultiValueConverter?ref=daveabrock.com">talks about the MultiConverter and the VariableMultiValueConverter</a>.</li><li>At Technology and Friends, <a href="https://www.davidgiard.com/2021/02/15/JulieLermanOnEntityFrameworkCore5.aspx?ref=daveabrock.com">David Giard talks with Julie Lerman</a>.</li><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Building-modern-hybrid-applications-with-Azure-Arc-and-Azure-Stack?ref=daveabrock.com">builds modern hybrid apps with Azure Arc and Azure Stack</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=1xLlUlmLgYs&ref=daveabrock.com">diagnose startup issues in Azure App Service</a>.</li><li>The ON.NET Show <a href="https://www.youtube.com/watch?v=LfPc0sitoR4&ref=daveabrock.com">creates GraphQL APIs with Hot Chocolate</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use Azure Functions with .NET 5 ]]></title>
        <description><![CDATA[ In this post, we upgrade a Functions app to .NET 5. ]]></description>
        <link>https://www.daveabrock.com/2021/02/24/functions-dotnet-5/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe90</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 23 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1508693484929-012827ef8c81?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDExfHxyb2NrZXR8ZW58MHx8fHwxNjE5ODI4MDM2&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>A little while ago, I <a href="https://daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis?ref=daveabrock.com">wrote a post</a> showing off how to use Open API and HttpRepl with ASP.NET Core 5 Web APIs. Using a new out-of-process model, you can now use .NET 5 with Azure Functions.</p><p>Traditionally, .NET support on Azure Functions has been tied to the Azure Functions runtime. You couldn’t just expect to use the new .NET version in your Functions as soon as it was released. As <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/net-5-support-on-azure-functions/ba-p/1973055?ref=daveabrock.com">Anthony Chu writes</a>, an updated version of the host is also required. Because .NET 5 is not LTS, and Microsoft needs to support specific releases for extended periods, they can’t upgrade the host to a non-LTS version because it isn’t supported for very long (15 months from the November 2020 release).</p><p>This doesn’t mean you can’t use .NET 5 with your Azure Functions. To do so, the team has rolled out a new out-of-process model that runs a worker process along the runtime. Because it runs in a separate process, you don’t have to worry about runtime and host dependencies. Looking long-term: it provides the ability to run the latest available version of .NET without waiting for a Functions upgrade.</p><p>There’s now an <a href="https://github.com/Azure/azure-functions-dotnet-worker-preview?ref=daveabrock.com">early preview of the .NET 5 worker</a>, with plans to be generally available in “early 2021.” I used the repository from my previous post to see how it works.</p><p><strong>Note</strong>: Before embarking on this adventure, you’ll need the <a href="https://dotnet.microsoft.com/download/dotnet/5.0?ref=daveabrock.com">.NET 5 SDK</a> installed as well as <a href="https://github.com/Azure/azure-functions-core-tools?ref=daveabrock.com">Azure Functions Core Tools</a> (a version &gt;= <code>3.0.3160</code>).</p><h2 id="update-local-settings-json">Update local.settings.json</h2><p>Update <code>local.settings.json</code> and change the <code>FUNCTIONS_WORKER_RUNTIME</code> to <code>dotnet-isolated</code>. This is likely a short-term fix, as the worker will be targeted to future .NET versions.</p><pre><code class="language-json">{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobsStorage": ""
}
</code></pre><h2 id="update-project-file">Update project file</h2><p>You’ll need to update your project file to the following:</p><pre><code class="language-xml">&lt;PropertyGroup&gt;
  &lt;TargetFramework&gt;net5.0&lt;/TargetFramework&gt;
  &lt;LangVersion&gt;preview&lt;/LangVersion&gt;
  &lt;AzureFunctionsVersion&gt;v3&lt;/AzureFunctionsVersion&gt;
  &lt;OutputType&gt;Exe&lt;/OutputType&gt;
  &lt;_FunctionsSkipCleanOutput&gt;true&lt;/_FunctionsSkipCleanOutput&gt;
&lt;/PropertyGroup&gt;
</code></pre><p>You might be wondering why the <code>OutputType</code> is <code>exe</code>. A .NET 5 Functions app is actually a .NET console app executable running in a separate process. Save that for Trivia Night. You’ll also note it uses the <code>v3</code> host and uses a <code>_FunctionsSkipCleanOutput</code> flag to preserve important files.</p><p>You’ll also need to update or install quite a few NuGet packages. It’ll probably be quickest to copy and paste these into your project file, save it, and let the NuGet restore process take over.</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.0.0-preview4" /&gt;
    &lt;PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.0-preview4" OutputItemType="Analyzer" /&gt;
    &lt;PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.0.12" /&gt;
    &lt;PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.3" /&gt;
    &lt;PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.2.0" /&gt;
    &lt;PackageReference Include="System.Net.NameResolution" Version="4.3.0" /&gt;
&lt;/ItemGroup&gt;
</code></pre><p>Lastly, you’ll need to include the following so the worker behaves correctly on Linux.</p><pre><code class="language-xml">&lt;Target Name="CopyRuntimes" AfterTargets="AfterBuild" Condition=" '$(OS)' == 'UNIX' "&gt;
    &lt;!-- To workaround a bug where the files aren't copied correctly for non-Windows platforms --&gt;
    &lt;Exec Command="rm -rf $(OutDir)bin/runtimes/* &amp;amp;&amp;amp; mkdir -p $(OutDir)bin/runtimes &amp;amp;&amp;amp; cp -R $(OutDir)runtimes/* $(OutDir)bin/runtimes/" /&gt;
&lt;/Target&gt;
</code></pre><h2 id="add-code-to-use-ef-in-memory-database">Add code to use EF in-memory database</h2><p>In my previous post, I used the Entity Framework in-memory database to quickly get going. I can add it just as easily in my Azure Function.</p><p>In my <code>Data</code> folder, I have an <code>ApiModels.cs</code> file to store my models as C# 9 records, a <code>SampleContext</code>, and a <code>SeedData</code> class.</p><p>The <code>ApiModels.cs</code>:</p><pre><code class="language-csharp">using System.ComponentModel.DataAnnotations;

namespace FunctionApp.Data
{
    public class ApiModels
    {
        public record Band(int Id, [Required] string Name);
    }
}
</code></pre><p>My <code>SampleContext.cs</code>:</p><pre><code class="language-csharp">using Microsoft.EntityFrameworkCore;

namespace FunctionApp.Data
{
    public class SampleContext : DbContext
    {
        public SampleContext(DbContextOptions&lt;SampleContext&gt; options)
            : base(options)
        {
        }

        public DbSet&lt;ApiModels.Band&gt; Bands { get; set; }
    }
}
</code></pre><p>And here’s the <code>SeedData</code> class:</p><pre><code class="language-csharp">using System.Linq;

namespace FunctionApp.Data
{
    public class SeedData
    {
        public static void Initialize(SampleContext context)
        {
            if (!context.Bands.Any())
            {
                context.Bands.AddRange(
                    new ApiModels.Band(1, "Led Zeppelin"),
                    new ApiModels.Band(2, "Arcade Fire"),
                    new ApiModels.Band(3, "The Who"),
                    new ApiModels.Band(4, "The Eagles, man")
                );

                context.SaveChanges();
            }
        }
    }
}
</code></pre><h2 id="enjoy-a-better-middleware-experience">Enjoy a better middleware experience</h2><p>With the new worker, I can enjoy a better dependency injection experience—I can finally do away with all that <code>[assembly: FunctionsStartup(typeof(Startup))]</code> business. It feels more natural, like I’m working in ASP.NET Core.</p><p>In <code>Program.cs</code>, I added a function to seed my database as startup time:</p><pre><code class="language-csharp">private static void SeedDatabase(IHost host)
{
    var scopeFactory = host.Services.GetRequiredService&lt;IServiceScopeFactory&gt;();

    using var scope = scopeFactory.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService&lt;SampleContext&gt;();

    if (context.Database.EnsureCreated())
    {
        try
        {
            SeedData.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = scope.ServiceProvideGetRequiredService&lt;ILogger&lt;Program&gt;&gt;();
            logger.LogError(ex, "A database seeding error occurred.");
        }
    }
}
</code></pre><p>In the <code>Main</code> method, I can inject services and work with my middleware. (More on that <code>Debugger.Launch()</code> later.)</p><pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;
using FunctionApp.Data;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Functions.Worker.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

static async Task Main(string[] args)
{
#if DEBUG
    Debugger.Launch();
#endif
    var host = new HostBuilder()
        .ConfigureAppConfiguration(c =&gt;
        {
            c.AddCommandLine(args);
        })
        .ConfigureFunctionsWorker((c, b) =&gt;
        {
            b.UseFunctionExecutionMiddleware();
        })
        .ConfigureServices(s =&gt;
        {
            s.AddSingleton&lt;IHttpResponderService, DefaultHttpResponderService&gt;();
            s.AddDbContext&lt;SampleContext&gt;(options =&gt;
                options.UseInMemoryDatabase("SampleData"));
        })
        .Build();
    SeedDatabase(host);

    await host.RunAsync();
}
</code></pre><h2 id="write-the-function">Write the function</h2><p>With all that out of the way, I can write my Function. I started with a get, but all the other endpoints from the previous post should follow the same pattern.</p><pre><code class="language-csharp">using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FunctionApp.Data;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;

namespace FunctionApp
{
    public class BandsFunction
    {
        private readonly SampleContext _context;

        public BandsFunction(SampleContext context)
        {
            _context = context;
        }

        [FunctionName("BandsGet")]
        public async Task&lt;List&lt;ApiModels.Band&gt;&gt; Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
            HttpRequestData req) =&gt;
                _context.Bands.ToList();
    }
}
</code></pre><p>This is a simple example, but as you dig a little more you’ll notice that in .NET 5 you’ll replace <code>HttpRequest</code> with <code>HttpRequestData</code> and <code>ILogger</code> with <code>FunctionExecutionContext</code>.</p><h2 id="about-the-tooling">About the tooling</h2><p>As with early preview capabilities, the tooling isn’t that far along. For example, right now you can’t expect to hit F5 in Visual Studio to debug your Function. To run the sample locally, you’ll need to use Azure Functions Core Tools from the command line.</p><p>From the prompt <code>cd</code> into the project directory and execute the following:</p><pre><code>func host start --verbose
</code></pre><p>To debug in Visual Studio, uncomment the <code>Debugger.Launch()</code> lines in <code>Program.cs</code> then run the command.</p><p>For VS Code, you’ll need to install the Functions extension, select the <code>Attach to .NET Functions</code> launch task, then start debugging.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, I introduced the new Functions worker, which allows you to use .NET 5 with your Azure Functions—and will allow more immediate release support in the future. We updated our project files, learned about the easier DI experience, and walked through the tooling experience. It takes some manual work to get this going, but tooling should improve throughout time.</p><p>Next, you can look into <a href="https://github.com/Azure/azure-functions-dotnet-worker-preview?ref=daveabrock.com#deploying-to-azure">deploying your app to Azure</a>. Right now, the team is warning you can <a href="https://github.com/Azure/azure-functions-dotnet-worker-preview?ref=daveabrock.com#deploying-to-azure">only do this for Windows plans and it isn’t completely optimized yet</a>.</p><p>Take a look at the GitHub repo for more details and for a sample app.</p><h2 id="references">References</h2><ul><li><a href="https://techcommunity.microsoft.com/t5/apps-on-azure/net-5-support-on-azure-functions/ba-p/1973055?ref=daveabrock.com">.NET 5 Support on Azure Functions</a> (Anthony Chu)</li><li><a href="https://github.com/Azure/azure-functions-dotnet-worker-preview?ref=daveabrock.com">Azure Functions .NET 5 Support</a> (GitHub)</li><li><a href="https://codetraveler.io/2021/02/12/creating-azure-functions-using-net-5/?ref=daveabrock.com">(Preview) Creating Azure Functions using .NET 5</a> (Brandon Minnick)</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Dev Discussions: Cecil Phillip ]]></title>
        <description><![CDATA[ We talk to Cecil Phillip about microservices and distributed systems. ]]></description>
        <link>https://www.daveabrock.com/2021/02/21/dev-discussions-cecil-phillip/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 20 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/cecil-phillip.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This is the full interview from my discussion with Cecil Phillip in my weekly (free!) newsletter, The .NET Stacks. Consider <a href="https://dotnetstacks.com/?ref=daveabrock.com">subscribing today</a>!</em></p><p>I recently had a chance to catch up with Cecil Phillip, a Senior Cloud Advocate for Microsoft. He’s a busy guy: you might have seen him co-hosting <a href="https://dotnet.microsoft.com/live/dotnet-docs?ref=daveabrock.com">The .NET Docs Show</a> or the <a href="https://channel9.msdn.com/Shows/On-NET?ref=daveabrock.com">ON.NET Show</a>. Cecil also does a lot with with microservices and distributed systems. I wanted to pick his brain on topics like Dapr, YARP, and Service Fabric. I hope you enjoy it.</p><h2 id="i-d-love-to-hear-about-how-you-got-in-this-field-and-ended-up-at-microsoft-">I’d love to hear about how you got in this field and ended up at Microsoft.</h2><p>I’ll try to give you a condensed version. Back in Antigua, we didn’t have computers in school at the time. One day, my dad brought home a <a href="https://en.wikipedia.org/wiki/Compaq_Presario?ref=daveabrock.com">Compaq Presario</a> to upgrade from using a typewriter that he used for working on his reports. Initially, I wasn’t allowed to “experiment” with the machine, so I’d explore it when he wasn’t around. I was so curious about what this machine could do, I wanted to know what every button did—and eventually, I got better at it than he was.</p><p>I went to college and got my CS degrees. I didn’t know I wanted to be a programmer. I didn’t know many examples of what CS folks did at the time. I got my first job working on ASP.NET Web Forms applications. After I got my green card, I spent a few years exploring different industries like HR, Finance, and Education. I taught some university courses in the evenings, and it was at that point I realized how much I loved teaching kids. Then one day, I saw a tweet about a new team at Microsoft, and I thought, “Why not?” I didn’t think I’d get the job, but I’d give it a try.</p><h2 id="when-it-comes-to-microservices-there-s-been-a-lot-of-talk-about-promoting-the-idea-of-loosely-coupled-monoliths-when-the-overhead-of-microservices-might-not-be-worth-it-what-are-your-thoughts">When it comes to microservices, there’s been a lot of talk about promoting the idea of “loosely coupled monoliths” when the overhead of microservices might not be worth it. What are your thoughts?</h2><p>Somewhere along the way, having your application get labeled as a monolith became a negative thing. In my opinion, we’ve learned a lot of interesting patterns that we can apply to both monoliths and microservices. For some solutions and teams, having a monolith is the right option. We can now pair that with the additional benefits of modern patterns to get some additional resiliency for a stable application.</p><h2 id="i-ve-been-reading-and-learning-about-yarp-a-net-reverse-proxy-why-would-i-use-this-over-something-like-nginx">I’ve been reading and learning about YARP, a .NET reverse proxy. Why would I use this over something like nginx?</h2><p>If you’re a .NET developer and want the ability to write custom rules or extensions for your reverse proxy/load balancer using your .NET expertise, then <a href="https://microsoft.github.io/reverse-proxy/articles/getting_started.html?ref=daveabrock.com">YARP</a> is a great tool.</p><h2 id="azure-front-door-seems-reverse-proxyish-why-should-i-choose-yarp-over-this">Azure Front Door seems reverse-proxy<em>ish</em>—why should I choose YARP over this?</h2><p><a href="https://azure.microsoft.com/services/frontdoor/?ref=daveabrock.com">Azure Front Door</a> is a great option if you’re running large-scale applications across multiple regions. It’s a hosted service with load balancing features, so you get things like SSL management, layer-7 routing, health checks, URL rewriting, and so on. YARP, on the other hand, is middleware for ASP.NET Core that implements some of those same reverse proxy concerns, but you’re responsible for your infrastructure and have to write code to enable your features. YARP would be more akin to something like <a href="http://www.haproxy.org/?ref=daveabrock.com">HAProxy</a> or <a href="https://nginx.org/en/?ref=daveabrock.com">nginx</a>.</p><h2 id="a-lot-of-enterprises-like-mine-use-nginx-for-an-aks-ingress-controller-will-yarp-ever-help-with-something-like-that">A lot of enterprises, like mine, use nginx for an AKS ingress controller. Will YARP ever help with something like that?</h2><p>Maybe. 🙂</p><h2 id="i-know-you-ve-also-been-working-with-dapr-i-know-it-simplifies-event-management-for-microservices-but-can-you-illustrate-how-it-can-help-net-developers-and-what-pain-points-it-solves">I know you’ve also been working with Dapr. I know it simplifies event management for microservices, but can you illustrate how it can help .NET developers and what pain points it solves?</h2><p>The biggest selling point for <a href="https://dapr.io/?ref=daveabrock.com">Dapr</a> is that it provides an abstraction over common needs for microservice developers. In the ecosystem today, there are tons of options to choose from to get a particular thing done— but with that comes tool-specific SDKs, APIs, and configuration. Dapr allows you to choose the combination of tools you want without needing to have your code rely on tool-specific SDKs. That includes things like messaging, secrets, service discovery, observability, actors, and so on.</p><h2 id="how-does-dapr-compare-with-something-like-service-fabric-is-there-overlap-and-do-you-see-dapr-someday-replacing-it">How does Dapr compare with something like Service Fabric? Is there overlap, and do you see Dapr someday replacing it?</h2><p>I look at Dapr and <a href="https://azure.microsoft.com/en-us/services/service-fabric/?ref=daveabrock.com">Service Fabric</a> as two completely different things. Dapr is an open-source, cross-platform CLI tool that provides building blocks for making microservice development easier. Service Fabric is a hosted Azure service that helps with packaging and deploying distributed applications. Dapr can run practically anywhere—on any cloud, on-premises, and Kubernetes. You can even run it on Service Fabric clusters since Service Fabric can run processes. It can run containers and even contains a programming model that applications can use as a hard dependency. Dapr itself is a process that would run beside your application’s various instances to provide some communication abstractions.</p><h2 id="what-is-your-one-piece-of-programming-advice">What is your one piece of programming advice?</h2><p>I think it’s important to spent time reading code. We should actually read more code than we write. There’s so we can learn and be inspired by exploring the techniques used by the developers that have come before us.</p><p><em>You can connect with Cecil Phillip <a href="https://twitter.com/cecilphillip?ref=daveabrock.com">on Twitter</a>.</em></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #37: 😲 When your private NuGet feed isn&#x27;t so private ]]></title>
        <description><![CDATA[ This week, we talk about a supply chain attack, container updates, Blazor REPL, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/02/20/dotnet-stacks-37/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 19 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-9.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Good morning to you. Is it summer yet? This week, I’m trying a new format: an in-depth topic, a lot of little things I’ve found, and, of course, the links. I appreciate any feedback you have.</p><ul><li>One big thing: A supply chain attack that should scare any company</li><li>The little things: Container updates, typed exceptions, Blazor REPL</li><li>Last week in the .NET world</li></ul><hr><h2 id="one-big-thing-a-supply-chain-attack-that-should-scare-any-company">One big thing: A supply chain attack that should scare any company</h2><p>When installing packages—whether over NPM, Python, and for us, NuGet—you’re happy not to have to deal with the complexities of dependency management personally. When you do this, you’re trusting publishers to install packages and code on your machine. When you install a package, do you ever wonder if this is open to exploits? It certainly is.</p><p>This week, Alex Birsan <a href="https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610?ref=daveabrock.com">wrote about</a> what he’s been working on for the last 6-7 months: hacking into dozens of companies—using a supply chain attack (or, as he calls it, <em>dependency confusion</em>). The ethical hack stems from a finding at Paypal last year, where Justin Gardner found that PayPal included private dependencies in a <code>package.json</code> hosted on GitHub. Those dependencies didn’t exist in the public NPM registry then, begging the question: what happens if you upload malicious code to NPM under those package names? Will the code get installed on PayPal-owned servers?</p><p>It isn’t just PayPal:</p><blockquote>Apparently, it is quite common for internal package.json files, which contain the names of a javascript project’s dependencies, to become embedded into public script files during their build process, exposing internal package names. Similarly, leaked internal paths or require() calls within these files may also contain dependency names. Apple, Yelp, and Tesla are just a few examples of companies who had internal names exposed in this way.</blockquote><p>It worked like a charm. <em>The .NET Stacks</em> is a family newsletter, so <a href="https://www.youtube.com/watch?v=cJhPbmtDfoE&ref=daveabrock.com">I’ll channel <em>The Good Place</em></a>: <strong>holy forking shirtballs</strong>.</p><blockquote>From one-off mistakes made by developers on their own machines, to misconfigured internal or cloud-based build servers, to systemically vulnerable development pipelines, one thing was clear: squatting valid internal package names was a nearly sure-fire method to get into the networks of some of the biggest tech companies out there, gaining remote code execution, and possibly allowing attackers to add backdoors during builds.</blockquote><p>I know what you’re thinking: <em>JavaScript is insecure. Is this where I pretend to be shocked</em>? The hack had impacts on .NET Core as well:</p><blockquote>Although this behavior was already commonly known, simply searching GitHub for –extra-index-url was enough to find a few vulnerable scripts belonging to large organizations — including a bug affecting a component of Microsoft’s .NET Core.</blockquote><p>From the .NET side, <a href="https://twitter.com/blowdart/status/1359221803453800468?s=20&ref=daveabrock.com">Barry Dorrans noted</a>:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/dorrans-attacks.jpg" class="kg-image" alt="Barry explains" loading="lazy" width="1482" height="1757" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/dorrans-attacks.jpg 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/dorrans-attacks.jpg 1000w, https://www.daveabrock.com/content/images/2021/05/dorrans-attacks.jpg 1482w" sizes="(min-width: 720px) 720px"></figure><p>So Microsoft fixed their problem. What about us? Microsoft has <a href="https://azure.microsoft.com/resources/3-ways-to-mitigate-risk-using-private-package-feeds/?ref=daveabrock.com">developed a whitepaper</a> for using private feeds. Their three suggestions for NuGet feeds:</p><ul><li>Reference a single private feed, not multiple, by using a single <code>&lt;add/&gt;</code> entry for a private feed in <code>nuget.config</code>, and a <code>&lt;clear /&gt;</code> entry to remove inherited configuration</li><li>Use controlled scopes using an ID prefix to restrict uploads to the public gallery</li><li>Use a <code>packages.lock.json</code> file to validate packages have not changed using version pinning and integrity checking.</li></ul><p>If you manage private NuGet feeds, make sure to heed the advice.</p><hr><h2 id="the-little-things-container-updates-typed-exceptions-blazor-repl">The little things: Container updates, typed exceptions, Blazor REPL</h2><p>If you’re like me, pulling containers from the Microsoft container registry is a simple process. I pull the images and move on. This week, Rich Lander <a href="https://devblogs.microsoft.com/dotnet/staying-safe-with-dotnet-containers/?ref=daveabrock.com">outlined the complexities</a> the team encounters. How hard can managing Dockerfiles be? When it comes to supporting a million<em>ish</em> pulls a month, it can be. A lot of the issues come with <a href="https://devblogs.microsoft.com/dotnet/staying-safe-with-dotnet-containers/?ref=daveabrock.com#vulnerabilities">tracking potential vulnerabilities</a> and how to manage them. He also offers some tips we can use: like rebuilding images frequently, reading CVE reports, and so on. It’s a long one but worth a read if you work with .NET container images.</p><p>On a related note, this week Mark Heath <a href="https://markheath.net/post/docker-tooling-vs2019?ref=daveabrock.com">wrote an excellent post</a> around Docker tooling for Visual Studio 2019.</p><p>–</p><p>In this week’s <a href="https://www.youtube.com/watch?v=aUl5QfswNU4&ref=daveabrock.com">Entity Framework community standup</a>, the team talked with Giorgi Dalakishvili about his <code>EntityFramework.Exceptions</code> project, which brings typed exceptions to Entity Framework Core. The project gets past digging into <code>DbUpdateException</code> to find your exact issue—whether it’s constraints, value types, or missing required values.</p><p>With <code>EntityFramework.Exceptions</code>, you can configure the <code>DbContext</code> to throw different exceptions, like <code>UniqueConstraintException</code> or <code>CannotInsertNullException</code>. It’s another great project where we wonder why it isn’t baked in, but happy it’s here.</p><p>–</p><p>Have you heard of <a href="https://github.com/BlazorRepl/BlazorRepl?ref=daveabrock.com">the Blazor REPL project</a>?</p><blockquote>Blazor REPL is a platform for writing, compiling, executing and sharing Blazor components entirely in the browser. It’s perfect for code playground and testing. It’s fast and secure. The platform is built and is running entirely on top of Blazor WASM - the WebAssembly hosting model of Blazor.</blockquote><p>You can write and run components right in the client. It’s perfect for you to test component libraries before you bring them into your project—the MudBlazor library has a site for this at <em><a href="https://try.mudblazor.com/snippet?ref=daveabrock.com">try.mudblazor.com</a></em>.</p><p>This week, <a href="https://twitter.com/BlazorREPL/status/1359177364001992705?ref=daveabrock.com">the Blazor REPL project teased</a> what’s coming—the ability to download NuGet packages and save public snippets.</p><p>–</p><p>ASP.NET Core architect David Fowler showed off some underrated .NET APIs for working with strings. I learned quite a bit, as I typically blindly use the same string methods all the time:</p><ul><li><code>StringBuilder.GetChunks</code>: you can <a href="https://t.co/HmOxJmc8PF?amp=1&ref=daveabrock.com">get access to the buffer</a> of the <code>StringBuilder</code></li><li><code>StringSplitOptions.TrimEntries</code>: you can split a string <a href="https://t.co/bVuM8b0YFT?amp=1&ref=daveabrock.com">without trimming each entry</a></li><li><code>Path.TrimEndingDirectorySeparator</code>: <a href="https://docs.microsoft.com/dotnet/api/system.io.path.trimendingdirectoryseparator?view=net-5.0&ref=daveabrock.com">eliminates you</a> manually checking for that trailing slash</li></ul><p>–</p><p>I recently <a href="https://twitter.com/JustinWGrote/status/1359214289962233857?s=20&ref=daveabrock.com">learned about</a> <em>github1s.com</em>, which allows you to browse code on GitHub with VS Code embedded in a browser for you. While you’re browsing a GitHub repo, change <em>github.com</em> to <em>github1s.com</em> to see it in action. Very nice.</p><hr><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/using-source-generators-to-find-all-routable-components-in-a-webassembly-app/?ref=daveabrock.com">uses source generators to find all routable components in a Blazor WebAssembly app</a>.</li><li>David McCarter <a href="https://www.c-sharpcorner.com/article/everything-you-want-to-know-about-the-record-type-in-net-5-but-were-afraid-to/?ref=daveabrock.com">goes deep on C# 9 records</a>.</li><li>Viktoria Grozdancheva <a href="https://www.telerik.com/blogs/how-to-unit-test-existing-csharp-app-easy-with-mocking-tool?ref=daveabrock.com">uses JustMock to mock C# unit tests</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>Rahul Bhandari <a href="https://devblogs.microsoft.com/dotnet/net-february-2021?ref=daveabrock.com">releases the .NET February 2021 updates</a>.</li><li>Microsoft announced <a href="https://azure.microsoft.com/blog/microsoft-will-establish-its-next-us-datacenter-region-in-georgia-s-fulton-and-douglas-counties/?ref=daveabrock.com">a new datacenter in Georgia</a> (the state in the US, not the country).</li><li>Simon Treanor <a href="https://simontreanor.github.io/blog/20210205_FunStripe.html?ref=daveabrock.com">rolls out FunStripe, an unofficial F# library for the Stripe API</a>.</li><li>Azure Cosmos DB is <a href="https://gotcosmos.com/conf?ref=daveabrock.com">getting their own conference</a> in April.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>Shameless plug: later today, I’ll be <a href="https://www.meetup.com/Bournemouth-ASP-NET-Blazor-Meetup-Group/events/275962302/?ref=daveabrock.com">speaking to the Bournemouth ASP.NET Blazor User Group</a> about my Blast Off with Blazor app.</li><li>Check out <em>k8s.af</em> for <a href="https://k8s.af/?ref=daveabrock.com">real-world Kubernetes failure stories</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=ekezoV4DcNA&ref=daveabrock.com">talks to Sophie Obomighie about APIs</a>.</li><li>In community standups, ASP.NET <a href="https://www.youtube.com/watch?v=v8UWYwAhKZA&ref=daveabrock.com">talks to Chris Sainty about his Blazor projects</a>, and Entity Framework <a href="https://www.youtube.com/watch?v=aUl5QfswNU4&ref=daveabrock.com">talks about typed exceptions</a>.</li><li>GitHub writes about <a href="https://github.blog/2021-02-11-how-we-designed-and-wrote-the-narrative-for-our-homepage/?ref=daveabrock.com">how they designed and wrote the narrative for their homepage</a>.</li><li>The Uno Platform team <a href="https://platform.uno/blog/sustaining-the-open-source-uno-platform/?ref=daveabrock.com">writes about sustaining their open-source project</a>.</li><li>Microsoft joins <a href="https://cloudblogs.microsoft.com/opensource/2021/02/08/microsoft-joins-rust-foundation?ref=daveabrock.com">as a founding member of the Rust Foundation</a>.</li><li>The Azure Dev Advocates <a href="https://dev.to/azure/blast-off-with-azure-advocates-presenting-the-azure-space-mystery-mdd?ref=daveabrock.com">released an Azure Space Mystery game</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Brady Gaster <a href="https://devblogs.microsoft.com/aspnet/open-source-http-api-packages-and-tools?ref=daveabrock.com">writes about open-source HTTP API packages and tools</a>.</li><li>Aram Tchekrekjian <a href="http://codingsonata.com/a-complete-tutorial-to-connect-android-with-asp-net-core-web-api/?ref=daveabrock.com">integrates an ASP.NET Core Web API with Android</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/ef-core-and-aspnet-core-cycle-issue-and-solution?ref=daveabrock.com">structures endpoints with ASP.NET Core and EF Core</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/rate-limiting-api-requests-with-asp-net-core-and-aspnetcoreratelimit/?ref=daveabrock.com">rate limits API requests with ASP.NET Core and AspNetCoreRateLimit</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/upload-files-to-azure-aspnet-core-blazor-webassembly/?ref=daveabrock.com">uploads files to Azure with .NET Core Web API and Blazor WebAssembly</a>, and also <a href="https://code-maze.com/download-files-from-azure-with-net-core-web-api-and-blazor-webassembly/?ref=daveabrock.com">downloads files with .NET Core Web API and Blazor WebAssembly</a>.</li><li>Xavier Geerinck <a href="https://blog.dapr.io/posts/2021/02/09/running-dapr-in-production-at-roadwork/?ref=daveabrock.com">writes about how Roadwork uses Dapr in production</a>.</li></ul><h3 id="-the-net-platform">🥅 The .NET platform</h3><ul><li>Richard Lander <a href="https://devblogs.microsoft.com/dotnet/staying-safe-with-dotnet-containers/?ref=daveabrock.com">writes about staying safe with .NET containers</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/upgrade-uwp-to-winui/?ref=daveabrock.com">writes about how to upgrade a UWP app to WinUI 3.0</a>.</li><li>Alexandre Zollinger Chohfi <a href="https://devblogs.microsoft.com/ifdef-windows/creating-a-windows-service-with-c-net5?ref=daveabrock.com">writes a Windows Service with C# and .NET 5</a>.</li><li>Thomas Claudius Huber <a href="https://www.thomasclaudiushuber.com/2021/02/05/what-is-actually-the-universal-windows-platform-and-what-is-winui-msix-and-project-reunion/?ref=daveabrock.com">writes about UWP, WinUI, MSIX, and Project Reunion</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Henk Boelman <a href="https://techcommunity.microsoft.com/t5/azure-ai/how-to-use-cognitive-services-and-containers/ba-p/2113684?ref=daveabrock.com">writes about using Cognitive Services and containers</a>.</li><li>Johnny Reilly <a href="https://blog.johnnyreilly.com/2021/02/azure-app-service-health-checks-and-zero-downtime-deployments.html?ref=daveabrock.com">works on zero downtime deployments with Azure App Service</a>.</li><li>Matt Ellis <a href="https://devblogs.microsoft.com/azure-sdk/custom-event-processor?ref=daveabrock.com">builds a custom Event Hubs event processor in .NET</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-Azure-Functions-Integration-With-SendGrid/?ref=daveabrock.com">integrates his Functions app with Azure SendGrid</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/02/08/secure-azure-ad-user-account-file-upload-with-azure-ad-storage-and-asp-net-core/?ref=daveabrock.com">secures Azure AD user file uploads with Azure AD storage and ASP.NET Core</a>.</li><li>Mahesh Chand <a href="https://www.c-sharpcorner.com/article/what-is-azure-functions/?ref=daveabrock.com">introduces Azure Functions</a>.</li><li>Jon Gallant <a href="https://blog.jongallant.com/2021/02/azure-rest-apis-postman-2021/?ref=daveabrock.com">uses the Azure APIs with Postman</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Simplify-If-Statements-with-Property-Pattern-Matching?ref=daveabrock.com">writes about property pattern matching in C#</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/193062-A/building-a-social-media-platform-without-going-bankrupt-part-x-optimizing-for-whales?Key=718095b6-a3fd-472c-aa28-6112d985f66f&ref=daveabrock.com">wraps up his series on writing a social media platform</a>.</li><li>Jeremy Clark <a href="https://jeremybytes.blogspot.com/2021/02/an-introduction-to-channels-in-c.html?ref=daveabrock.com">introduces channels in C#</a>, and also <a href="https://jeremybytes.blogspot.com/2021/02/whats-difference-between-channel-and.html?ref=daveabrock.com">differentiates Channel and ConcurrentQueue</a>.</li><li>Mark-James McDougall <a href="https://markjames.dev/2021-02-09-iracing-telemetry-fsharp/?ref=daveabrock.com">works on iRacing telemetry in F#</a>.</li><li>Isaac Abraham <a href="https://www.compositional-it.com/news-blog/custom-equality-and-comparison-in-f/?ref=daveabrock.com">writes about custom equality and comparison in F#</a>.</li><li>Urs Enzler <a href="https://www.planetgeek.ch/2021/02/11/our-journey-to-f-libraries-we-use/?ref=daveabrock.com">writes about F# libraries he uses</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/bebop-with-csharp?ref=daveabrock.com">uses Bebop with a C# TCP server</a>.</li><li>Tobias Günther <a href="https://www.smashingmagazine.com/2021/02/getting-the-most-out-of-git/?ref=daveabrock.com">gets the most out of Git</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/get-on-the-windows-terminal-preview-train-now-with-settings-ui?ref=daveabrock.com">writes about what’s new with Windows Terminal</a>.</li><li>Rachel Appel <a href="https://blog.jetbrains.com/dotnet/2021/02/08/make-code-more-readable-by-refactoring-with-resharper/?ref=daveabrock.com">shows off ReSharper</a>.</li><li>Horatiu Vladasel <a href="https://www.advancedinstaller.com/msix-package-in-visual-studio.html?ref=daveabrock.com">creates an MSIX package in Visual Studio</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/tiny-toplevel-programs-with-c-9-and-smallsharp-and-visual-studio?ref=daveabrock.com">works on tiny top-level programs with C# 9 and SmallSharp and Visual Studio</a>.</li><li>Thomas Cladius Huber <a href="https://www.thomasclaudiushuber.com/2021/02/06/configure-naming-styles-and-rules-in-visual-studio-and-also-at-the-solution-project-level-with-an-editorconfig-file/?ref=daveabrock.com">works with .editorconfig settings in Visual Studio</a>.</li><li>Mark Heath <a href="https://markheath.net/post/docker-tooling-vs2019?ref=daveabrock.com">writes about Visual Studio 2019 Docker tooling</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Sam Basu <a href="https://www.telerik.com/blogs/custom-xamarin-controls-blazor-mobile-bindings?ref=daveabrock.com">works with custom Xamarin controls with Blazor Mobile Bindings</a>.</li><li>James Montemagno <a href="https://montemagno.com/cross-platform-in-app-purchases-for-xamarin-mac-apps/?ref=daveabrock.com">works on cross-plat in-app purchases for Xamarin.Mac</a>.</li><li>Luis Matos <a href="https://luismts.com/stickyheader-xamarin-forms/?ref=daveabrock.com">uses sticky headers and navigation bars</a>.</li></ul><h3 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Patrick Smacchia <a href="https://blog.ndepend.com/10-reasons-why-you-should-write-tests/?ref=daveabrock.com">writes about why you should write tests</a>.</li><li>Steve Smith <a href="https://ardalis.com/keep-tests-short-and-dry-with-extensions/?ref=daveabrock.com">uses extension methods to keep tests short and DRY</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/aggregate-root-design-behavior-data/?ref=daveabrock.com">talks about persisting Aggregates</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/my-experience-of-using-modular-monolith-and-ddd-architectures/?ref=daveabrock.com">writes about his experience using modular monoliths and DDD architectures</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The Xamarin Podcast <a href="https://www.xamarinpodcast.com/87?ref=daveabrock.com">has a Xamarin Community Toolkit extravaganza</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-055-microservices-or-should-they-be-called-single-responsibility-services-w-christian-horsdal/?ref=daveabrock.com">talks about microservices</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-182-application-security-with-tanya-janca/?ref=daveabrock.com">talks about application security with Tanya Janca</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1726&ref=daveabrock.com">talks with Phil Haack</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/is-blazor-ready-for-prime-time-episode-127?ref=daveabrock.com">talks to Jeff Fritz about Blazor WebAssembly architecture</a>.</li><li>The .NET Core Podcast <a href="https://dotnetcore.show/episode-69-the-risks-of-third-party-code-with-niels-tanis/?ref=daveabrock.com">talks to Niels Tanis about the risks of third party code</a>.</li><li>The Productive C# Podcast <a href="https://anchor.fm/productivecsharp/episodes/16--The-Mikado-Method-eq0iek?ref=daveabrock.com">talks about The Mikado Method</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>The ON.NET Show <a href="https://www.youtube.com/watch?v=SCR1IdW0PCk&ref=daveabrock.com">generates docs for ASP.NET Core Web APIs with Swashbuckle</a>.</li><li>The Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Analyzing-Code-with-Infer?ref=daveabrock.com">analyzes code with Infer#</a>.</li><li>The Loosely Coupled Show <a href="https://www.youtube.com/watch?v=nmvadY1OPOQ&ref=daveabrock.com">talks about various domains and projects they’ve worked on</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=gpi-h-2GJ7w&ref=daveabrock.com">talks to Chris Patterson about MassTransit</a>.</li><li>Technology and Friends <a href="https://www.davidgiard.com/2021/02/08/KevinPilchOnGRPC.aspx?ref=daveabrock.com">talks to Kevin Pilch about gRPC</a>.</li><li>Azure Friday <a href="https://channel9.msdn.com/Shows/Azure-Friday/Operational-best-practices-for-web-apps-on-Azure-App-Service?ref=daveabrock.com">discusses operational best practices for Azure App Service</a>, and also <a href="https://channel9.msdn.com/Shows/Azure-Friday/Scale-Your-Cloud-App-with-Azure-Cache-for-Redis?ref=daveabrock.com">scales apps with Azure Cache for Redis</a>.</li><li>Web Wednesday <a href="https://channel9.msdn.com/Shows/Web-Wednesday/What-is-Tailwind-CSS?ref=daveabrock.com">introduces Tailwind CSS</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Build a Blazor &#x27;Copy to Clipboard&#x27; component with a Markdown editor ]]></title>
        <description><![CDATA[ Let&#39;s build a &#39;Copy to Clipboard&#39; component, where we can copy Markdown content to the clipboard. ]]></description>
        <link>https://www.daveabrock.com/2021/02/18/copy-to-clipboard-markdown-editor/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 17 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1568847811512-803314424fdc?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGNsaXBib2FyZHxlbnwwfHx8fDE2MTk4MzI2ODk&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>I recently built a quick utility app for the day job, where I used a simple Markdown previewer with a <em>Copy to Clipboard</em> button. I use the button to notify if the copy is successful. Then, I return the button to its original state.</p><p>Here’s how the app looks when it works correctly.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/clipboard-success.gif" class="kg-image" alt="A successful copy" loading="lazy" width="1258" height="512"></figure><p>And here’s how it looks when the copy fails.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/clipboard-error.gif" class="kg-image" alt="A failed copy" loading="lazy" width="1506" height="386"></figure><p>We’ll build a component that allows users to copy and paste text from a markdown previewer. This process involves three steps:</p><ul><li>Implement a <code>ClipboardService</code></li><li>Create a shared <code>CopyToClipboardButton</code> component</li><li>Use the component with a markdown previewer</li></ul><p>The code is <a href="https://github.com/daveabrock/ClipboardSample?ref=daveabrock.com">out on GitHub</a> if you’d like to play along.</p><h2 id="implement-a-clipboardservice">Implement a ClipboardService</h2><p>To write text to the clipboard, we’ll need to use a browser API. This work involves some quick JavaScript, whether from a pre-built component or some JavaScript interoperability. Luckily for us, we can create a basic <code>ClipboardService</code> that allows us to use <code>IJsRuntime</code> to call the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API?ref=daveabrock.com">Clipboard API</a>, which <a href="https://caniuse.com/mdn-api_clipboard_writetext?ref=daveabrock.com">is widely used</a> in today’s browsers.</p><p>We’ll create a <code>WriteTextAsync</code> method that takes in the text to copy. Then, we’ll write the text to the API with a <em>navigator.clipboard.writeText</em> call. Here’s the code for <code>Services/ClipboardService.cs</code>:</p><pre><code class="language-csharp">using System.Threading.Tasks;
using Microsoft.JSInterop;

namespace ClipboardSample.Services
{
    public class ClipboardService
    {
        private readonly IJSRuntime _jsRuntime;

        public ClipboardService(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }

        public ValueTask WriteTextAsync(string text)
        {
            return _jsRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text);
        }
    }
}
</code></pre><p>Then, in <code>Program.cs</code>, reference the new service we created:</p><pre><code class="language-csharp">builder.Services.AddScoped&lt;Services.ClipboardService&gt;();
</code></pre><p>With that out of the way, let’s create the <code>CopyToClipboardButton</code> component.</p><h2 id="create-a-shared-copytoclipboardbutton-component">Create a shared CopyToClipboardButton component</h2><p>To create a shared component, create a <code>CopyToClipboardButton</code> component in your project’s shared directory.</p><p>Thanks to <a href="https://twitter.com/meziantou?ref=daveabrock.com">Gérald Barré</a> for his excellent input on working with button state. Check out <a href="https://www.meziantou.net/?ref=daveabrock.com">his site</a> for great ASP.NET Core and Blazor content.</p><p>At the top of the file, let’s inject our <code>ClipboardService</code>. (We won’t need a <code>@page</code> directive since this will be a shared component and not a routable page.)</p><pre><code>@inject ClipboardService ClipboardService
</code></pre><p>Now, we’ll need to understand how the button will look. For both the active and notification states, we need to have the following:</p><ul><li>Message to display</li><li>Font Awesome icon to display</li><li>Bootstrap button class</li></ul><p>With that in mind, let’s define all those at the beginning of the component’s <code>@code</code> block. (This could be in a separate file, too, if you wish.)</p><pre><code class="language-csharp">@code {
    private const string _successButtonClass = "btn btn-success";
    private const string _infoButtonClass = "btn btn-info";
    private const string _errorButtonClass = "btn btn-danger";

    private const string _copyToClipboardText = "Copy to clipboard";
    private const string _copiedToClipboardText = "Copied to clipboard!";
    private const string _errorText = "Oops. Try again.";

    private const string _fontAwesomeCopyClass = "fa fa-clipboard";
    private const string _fontAwesomeCopiedClass = "fa fa-check";
    private const string _fontAwesomeErrorClass = "fa fa-exclamation-circle";
</code></pre><p>With that, we need to include a <code>Text</code> property as a component parameter. The caller will provide this to us, so we know what to copy.</p><pre><code>[Parameter] 
public string Text { get; set; }
</code></pre><p>Through the joy of C# 9 records and target typing, we can create an immutable object to work with the initial state.</p><pre><code class="language-csharp">record ButtonData(bool IsDisabled, string ButtonText,
        string ButtonClass, string FontAwesomeClass);

ButtonData buttonData = new(false, _copyToClipboardText,
                      _infoButtonClass, _fontAwesomeCopyClass);
</code></pre><p>Now, in the markup, we can add a new button with the properties we defined.</p><pre><code class="language-html">&lt;button class="@buttonData.ButtonClass" disabled="@buttonData.IsDisabled" 
        @onclick="CopyToClipboard"&gt;
    &lt;i class="@buttonData.FontAwesomeClass"&gt;&lt;/i&gt; @buttonData.ButtonText
&lt;/button&gt; 
</code></pre><p>You’ll get an error because your editor doesn’t know about the <code>CopyToClipboard</code> method. Let’s create it.</p><p>First, set up an <code>originalData</code> variable that holds the original state, so we have it when it changes.</p><pre><code class="language-csharp">var originalData = buttonData;
</code></pre><p>Now, we’ll do the following in a try/catch block:</p><ul><li>Write the text to the clipboard</li><li>Update <code>buttonData</code> to show it was a success/failure</li><li>Call <code>StateHasChanged</code></li><li>Wait 1500 milliseconds</li><li>Return <code>buttonData</code> to its original state</li></ul><p>We need to explicitly call <code>StateHasChanged</code> to notify the component it needs to re-render because the state … has changed.</p><p>Here’s the full <code>CopyToClipboard</code> method (along with a <code>TriggerButtonState</code> private method for reusability).</p><pre><code class="language-csharp">public async Task CopyToClipboard()
{
    var originalData = buttonData;
    try
    {
        await ClipboardService.WriteTextAsync(Text);

        buttonData = new ButtonData(true, _copiedToClipboardText,
                                    _successButtonClass, _fontAwesomeCopiedClass);
        await TriggerButtonState();
        buttonData = originalData;
    }
    catch
    {
        buttonData = new ButtonData(true, _errorText,
                                    _errorButtonClass, _fontAwesomeErrorClass);
        await TriggerButtonState();
        buttonData = originalData;
    }
}

private async Task TriggerButtonState()
{
    StateHasChanged();
    await Task.Delay(TimeSpan.FromMilliseconds(1500));
}
</code></pre><p>For reference, here’s the entire <code>CopyToClipboardButton</code> component:</p><pre><code class="language-csharp">@inject ClipboardService ClipboardService

&lt;button class="@buttonData.ButtonClass" disabled="@buttonData.IsDisabled" 
        @onclick="CopyToClipboard"&gt;
    &lt;i class="@buttonData.FontAwesomeClass"&gt;&lt;/i&gt; @buttonData.ButtonText
&lt;/button&gt; 
&lt;br/&gt;&lt;br /&gt;

@code {
    private const string _successButtonClass = "btn btn-success";
    private const string _infoButtonClass = "btn btn-info";
    private const string _errorButtonClass = "btn btn-danger";

    private const string _copyToClipboardText = "Copy to clipboard";
    private const string _copiedToClipboardText = "Copied to clipboard!";
    private const string _errorText = "Oops. Try again.";

    private const string _fontAwesomeCopyClass = "fa fa-clipboard";
    private const string _fontAwesomeCopiedClass = "fa fa-check";
    private const string _fontAwesomeErrorClass = "fa fa-exclamation-circle";

    [Parameter] 
    public string Text { get; set; }

    record ButtonData(bool IsDisabled, string ButtonText,
        string ButtonClass, string FontAwesomeClass);

    ButtonData buttonData = new(false, _copyToClipboardText,
                      _infoButtonClass, _fontAwesomeCopyClass);

    public async Task CopyToClipboard()
    {
        var originalData = buttonData;
        try
        {
            await ClipboardService.WriteTextAsync(Text);

            buttonData = new ButtonData(true, _copiedToClipboardText,
                                    _successButtonClass, _fontAwesomeCopiedClass);
            await TriggerButtonState();
            buttonData = originalData;
        }
        catch
        {
            buttonData = new ButtonData(true, _errorText,
                                    _errorButtonClass, _fontAwesomeErrorClass);
            await TriggerButtonState();
            buttonData = originalData;
        }
    }

    private async Task TriggerButtonState()
    {
        StateHasChanged();
        await Task.Delay(TimeSpan.FromMilliseconds(1500));
    }
}
</code></pre><p>Great! You should now be able to see the button in action. If you need help triggering a failed state, you can go back to <code>ClipboardService</code> and spell the JS function wrong:</p><pre><code class="language-csharp">return _jsRuntime.InvokeVoidAsync("navigatoooooor.clipboard.writeText", text);
</code></pre><p>That’s great, but our component doesn’t do anything meaningful. To do that, we can attach it to a Markdown previewer.</p><h2 id="use-the-component-with-a-markdown-previewer">Use the component with a markdown previewer</h2><p>We can now build a simple markdown previewer with the <a href="https://github.com/xoofx/markdig?ref=daveabrock.com">Markdig library</a>. This allows us to convert markdown to HTML to see the final state of our rendered Markdown state.</p><p>Thanks to Jon Hilton’s excellent post, <a href="https://jonhilton.net/blazor-markdown-editor/?ref=daveabrock.com">I was able to do this in minutes</a>. I’ll quickly add the component here—if you want greater explanation or context, please visit Jon’s post (another great site for Blazor content).</p><p>After you <a href="https://www.nuget.org/packages/Markdig/?ref=daveabrock.com">download the Markdig package</a> and add a <code>@using Markdig</code> line to your <code>_Imports.razor</code>, create an <code>Editor.razor</code> component with something like this:</p><pre><code class="language-html">@page "/clipboard"

&lt;div class="row"&gt;
    &lt;div class="col-6" height="100"&gt;
        &lt;textarea class="form-control" 
        @bind-value="Body" 
        @bind-value:event="oninput"&gt;&lt;/textarea&gt;
    &lt;/div&gt;
    &lt;div class="col-6"&gt;
        @((MarkupString) Preview)
    &lt;/div&gt;
&lt;/div&gt;

@code {
    public string Body { get; set; } = string.Empty;
    public string Preview =&gt; Markdown.ToHtml(Body);
}
</code></pre><p>Long story short, I’m adding a <code>text-area</code> for writing Markdown, binding to the <code>Body</code> text. Then as a user types (the <code>event="oninput</code>), use Markdig to render HTML in the other pane on the right.</p><p>All we need to do now is include our new component, and pass the <code>Body</code> along. Add the following just below the <code>@page</code> directive and before the <code>div</code>:</p><pre><code>&lt;CopyToClipboardButton 
    Text="@Body" /&gt;
</code></pre><p>As a reference, here’s the full <code>Editor.razor</code> file:</p><pre><code class="language-html">@page "/editor"

&lt;CopyToClipboardButton 
    Text="@Body" /&gt;

&lt;div class="row"&gt;
    &lt;div class="col-6" height="100"&gt;
        &lt;textarea class="form-control" 
        @bind-value="Body" 
        @bind-value:event="oninput"&gt;&lt;/textarea&gt;
    &lt;/div&gt;
    &lt;div class="col-6"&gt;
        @((MarkupString) Preview)
    &lt;/div&gt;
&lt;/div&gt;

@code {
    public string Body { get; set; } = string.Empty;
    public string Preview =&gt; Markdown.ToHtml(Body);
}
</code></pre><p>That’s really all there is to it!</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we built a reusable component to copy text to the clipboard. As a bonus, the component toggles between active and notification states. We also saw how simple it was to attach it to a Markdown previewer.</p><p>There’s more we could do: for example, can we make the component more reusable by passing in button text and states—making it a ButtonToggleState component and not just used for copying to a clipboard? Give it a shot and let me know how it goes!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #36: ⚡ Azure Functions and some Microsoft history ]]></title>
        <description><![CDATA[ This week, we talk about Azure Functions, Blazor, and some Microsoft history. ]]></description>
        <link>https://www.daveabrock.com/2021/02/13/dotnet-stacks-36/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 12 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-10.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another week. If you’re seeing temperatures above above 0° F, please send some my way. Talk about a cold start—Azure Functions should be jealous.</p><p>This week:</p><ul><li>OpenAPI support for Azure Functions</li><li>Achieving inheritance with Blazor CSS isolation</li><li>Ignoring calls from Bill Gates</li></ul><h2 id="open-api-support-for-azure-functions">Open API support for Azure Functions</h2><p>When you create a new ASP.NET Core Web API in .NET 5, you may have noticed that Open API (more commonly to you, Swagger UI) is supported out of the box—and there’s a handy check mark in Visual Studio to guide you along. You might be wondering: will Open API support come to Azure Functions?</p><p>The answer is yes. While it’s very much in preview, the team’s <a href="https://twitter.com/bradygaster/status/1356706555735887876?ref=daveabrock.com">been talking about</a> releasing Open API bindings for Functions. This idea <a href="https://devkimchi.com/2019/02/02/introducing-swagger-ui-on-azure-functions/?ref=daveabrock.com">isn’t anything new</a>, but the bindings look promising.</p><p>With bindings, you’ll be able to <a href="https://github.com/Azure/azure-functions-openapi-extension/blob/main/docs/openapi-core.md?ref=daveabrock.com#expose-endpoints-to-open-api-document">decorate your functions with bindings like</a>:</p><ul><li><code>[OpenApiOperation("addStuff", "stuff")]</code></li><li><code>[OpenApiRequestBody("application/json", typeof(MyRequestModel))]</code></li><li><code>[OpenApiResponseBody(HttpStatusCode.OK, "application/json", typeof(MyResponseModel))]</code></li></ul><p>I’m seeing <a href="https://github.com/Azure/azure-functions-openapi-extension/blob/main/docs/openapi-core.md?ref=daveabrock.com#supported-jsonnet-decorators">JSON.NET decorators</a> (hat tip to the team for not pushing <code>System.Text.Json</code> on us), <a href="https://github.com/Azure/azure-functions-openapi-extension/blob/main/docs/openapi-core.md?ref=daveabrock.com#open-api-metadata-configuration">optional metadata configuration</a>, and <a href="https://github.com/Azure/azure-functions-openapi-extension/blob/main/docs/openapi-core.md?ref=daveabrock.com#openapisecurityattribute">security and authentication support</a>. It’s early, so if you do try it out be patient and report issues as you come across them.</p><h2 id="achieving-inheritance-with-blazor-css-isolation">Achieving inheritance with Blazor CSS isolation</h2><p>After <a href="https://daveabrock.com/2020/09/10/blazor-css-isolation?ref=daveabrock.com">writing</a> <a href="https://docs.microsoft.com/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0&ref=daveabrock.com">about</a> Blazor CSS isolation over the last few months I’ve received a common question: how do I achieve inheritance with CSS isolation? I <a href="https://daveabrock.com/2021/01/31/blazor-css-iso-inheritance-scopes?ref=daveabrock.com">wrote about it this week</a>.</p><p>The concept is a little weird—isolation scopes CSS to your components, and “inheriting” or sharing styles across components seems to go against a lot of those advantages. Even so, in some limited scenarios, it can help maintenance when dealing with similarly grouped components.</p><p>From the post (quoting myself in my newsletter deserves a trip to the therapist, I must admit):</p><blockquote>If we’re honest, with Blazor CSS isolation, the “C” (cascading) is non-existent. There’s no cascading going on here—isolating your styles is the opposite of cascading. With Blazor CSS isolation, you scope your CSS component styles. Then, at build time, Blazor takes care of the cascading for you. When you wish to inherit styles and share them between components, you’re losing many of the advantages of using scoped CSS.</blockquote><blockquote>In my opinion, using inheritance with CSS isolation works best when you want to share styles across a small group of similar components. If you have 500 components in your solution and you want to have base styles across them all, you may be creating more problems for yourself. In those cases, you should stick with your existing tools.</blockquote><p>With those caveats aside, how do you do it? The key here is that Blazor CSS isolation is <em>file</em>-based, not class-based, so it doesn’t know about your object graph. This is done with grouping custom scope identifiers, which you can add to your project file. I’ve included these updates <a href="https://daveabrock.com/2021/01/31/blazor-css-iso-inheritance-scopes?ref=daveabrock.com">in this week’s blog post</a> and in the official Microsoft ASP.NET Core doc.</p><h2 id="ignoring-calls-from-bill-gates">Ignoring calls from Bill Gates</h2><p>I’ve really been enjoying reading Steven Sinofsky. A former Microsoft veteran—with stories to share from building out Windows in the antitrust years—he’s writing a serialized book on Substack, <em><a href="https://hardcoresoftware.learningbyshipping.com/?ref=daveabrock.com">Hardcore Software</a></em>. It’ll be split into 15 chapters and an epilogue. In his first chapter he writes about joining Microsoft. He never returned calls from Bill Gates because he thought his friends were pranking him. When he finally did, <a href="https://hardcoresoftware.learningbyshipping.com/p/001-becoming-a-microsoftie-chapter?ref=daveabrock.com">he was met with some hilarious frankness</a>:</p><blockquote>“Hi, Steve, this is Bill Gates.” … “Hello. Thank you for calling, and so sorry for the confusion. I thought a friend of mine…”</blockquote><blockquote>“So, David gave me this list of like ten people and I’m supposed to call all of them and convince them to work at Microsoft. You should come work at Microsoft. Do you have any questions?”</blockquote><blockquote>“Well, why haven’t you accepted yet? You have a good offer.”</blockquote><blockquote>“I’m considering other things. I have been really interested in government service.”</blockquote><blockquote>“Government? That’s for when you’re old and stupid.”</blockquote><p>This is a fun history lesson and I’m looking forward to reading it all.</p><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-4">🔥 The Top 4</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/finding-all-routable-components-in-a-webassembly-app/?ref=daveabrock.com">finds all routable components in a Blazor app</a>.</li><li>Oren Eini continues writing a social media platform as he <a href="https://ayende.com/blog/193061-A/building-a-social-media-platform-without-going-bankrupt-part-ix-dealing-with-the-past?Key=1e50fc85-8fba-42d7-9db8-3236e5f396fc&ref=daveabrock.com">deals with the past</a>, <a href="https://ayende.com/blog/193060-A/building-a-social-media-platform-without-going-bankrupt-part-viii-tagging-and-searching?Key=c69d9fb8-89e6-4d4c-a4a8-2b3b37386c36&ref=daveabrock.com">tags and searches</a>, <a href="https://ayende.com/blog/193058-A/building-a-social-media-platform-without-going-bankrupt-part-vi-dealing-with-edits-and-deletions?Key=107bae9f-a2f2-49bb-bc49-4a4338156e98&ref=daveabrock.com">works with edits and deletions</a>, <a href="https://ayende.com/blog/193059-A/building-a-social-media-platform-without-going-bankrupt-part-vii-counting-views-replies-and-likes?ref=daveabrock.com">counts replies and likes</a>, and <a href="https://ayende.com/blog/193057-A/building-a-social-media-platform-without-going-bankrupt-part-v-handling-the-timeline?Key=f24ec06d-5d24-49ba-9a90-2809f6b55c3f&ref=daveabrock.com">handles the timeline</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/02/01/implement-app-roles-authorization-with-azure-ad-and-asp-net-core/?ref=daveabrock.com">implements app role authorization with Azure AD and ASP.NET Core</a>.</li><li>Stephen Cleary <a href="https://blog.stephencleary.com/2021/02/asynchronous-messaging-5-miscellaneous-considerations.html?ref=daveabrock.com">continues writing about asynchronous messaging</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>David Ortinau <a href="https://devblogs.microsoft.com/xamarin/the-new-net-multi-platform-app-ui-maui?ref=daveabrock.com">provides a MAUI update</a>.</li><li>Scott Addie <a href="https://docs.microsoft.com/aspnet/core/whats-new/2021-01?view=aspnetcore-5.0&ref=daveabrock.com">provides a rundown of what’s new in the ASP.NET Core docs</a>.</li><li>Azure Event Grid <a href="https://azure.microsoft.com/updates/azure-event-grid-is-now-in-public-preview-for-azure-cache-for-redis?ref=daveabrock.com">is now in public preview for Azure Cache for Redis</a>.</li><li>Dapr <a href="https://blog.dapr.io/posts/2021/02/03/dapr-v1.0.0-rc.3-is-now-available/?ref=daveabrock.com">v1.0.0-rc.3 is now available</a>.</li><li>The January 2021 <a href="https://code.visualstudio.com/updates/v1_53?ref=daveabrock.com">release of VS Code is out</a>.</li><li>Redgate announces <a href="https://www.red-gate.com/blog/redgate-events/redgate-pass?ref=daveabrock.com">they are committing to the future of PASS</a>.</li><li>Microsoft released <a href="https://www.onmsft.com/news/powertoys-0-31-1-is-now-available-with-better-fancyzone-editor?ref=daveabrock.com">PowerToys 0.31.1, with a better FancyZone editor</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>If you didn’t know, GitHub discussions area thing. Now that you know they are a thing, the ASP.NET Core team <a href="https://github.com/dotnet/aspnetcore/issues/29935?ref=daveabrock.com">has stopped using them</a>.</li><li>Microsoft Ignite <a href="https://t.co/eKAF5ApaZH?amp=1&ref=daveabrock.com">registration is open</a>.</li><li>JetBrains <a href="https://blog.jetbrains.com/dotnet/2021/02/01/rider-2021-1-eap/?ref=daveabrock.com">released 2020.1 EAP for Rider</a> and also <a href="https://blog.jetbrains.com/dotnet/2021/02/01/resharper-2021-1-starts-eap/?ref=daveabrock.com">2020.1 EAP for ReSharper</a>.</li><li>For community standups, we’ve got Xamarin <a href="https://www.youtube.com/watch?v=n12JoSn31Ac&ref=daveabrock.com">talking about Community Toolkit updates</a>, Machine Learning <a href="https://www.youtube.com/watch?v=JeX7BhBPoUE&ref=daveabrock.com">talking about Jupyter and .NET Interactive</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=VkJQR854S1s&ref=daveabrock.com">talks about Dapr</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=XBp4pNc1Q4g&ref=daveabrock.com">automates kombucha availability with .NET</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Dave Brock <a href="https://daveabrock.com/2021/01/31/blazor-css-iso-inheritance-scopes?ref=daveabrock.com">writes about how to achieve style inheritance with Blazor CSS isolation</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-netlify?ref=daveabrock.com">deploys Blazor WASM apps to Netlify</a>.</li><li>Imar Spaanjars <a href="https://imar.spaanjaars.com/619/building-and-auto-deploying-an-aspnet-core-application-part-2-creating-the-web-application?ref=daveabrock.com">builds and auto-deploys an ASP.NET Core app</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/blazor/blash-twitter-dashboard-using-blazor-web-api-signalr-twitter-api?ref=daveabrock.com">starts writing about Blash, a Twitter dashboard</a>.</li><li>Brady Gaster <a href="https://devblogs.microsoft.com/aspnet/creating-discoverable-http-apis-with-asp-net-core-5-web-api?ref=daveabrock.com">creates discoverable APIs with ASP.NET Core 5 Web API</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/facebook-authentication-in-blazor-webassembly-hosted-applications/?ref=daveabrock.com">works on Facebook auth in Blazor WebAssembly hosted applications</a>, and also <a href="https://code-maze.com/google-authentication-in-blazor-webassembly-hosted-applications/?ref=daveabrock.com">works with Google auth as well</a>.</li><li>Daniel Jimenez Garcia <a href="https://www.dotnetcurry.com/aspnet-core/kuberenetes-for-developers?ref=daveabrock.com">writes about Kubernetes for ASP.NET Core developers</a>.</li><li>Eve Turzillo <a href="https://www.telerik.com/blogs/how-to-effectively-debug-three-common-website-issues-using-web-debugging-proxy-tool?ref=daveabrock.com">writes about strategies for debugging common website issues</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/aspnet-core-ioptions-configuration?ref=daveabrock.com">works with IOptions in ASP.NET Core</a>.</li><li>Tobias Ahlin <a href="https://github.blog/2021-01-29-making-githubs-new-homepage-fast-and-performant/?ref=daveabrock.com">continues writing about GitHub’s new homepage</a>.</li></ul><h3 id="-the-net-platform">🥅 The .NET platform</h3><ul><li>Alexandre Zollinger Chohfi <a href="https://devblogs.microsoft.com/pax-windows/command-line-parser-on-net5?ref=daveabrock.com">writes about command line parsing in .NET 5</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/02/03/net-6-desktop.aspx?ref=daveabrock.com">writes about .NET 6 desktop dev options</a>.</li><li>Peter Mbanugo <a href="https://www.telerik.com/blogs/introduction-to-grpc-dotnet-core-and-dotnet-5?ref=daveabrock.com">introduces gRPC in .NET Core and .NET 5</a>.</li><li>Konrad Kokosa <a href="https://tooslowexception.com/net-gc-internals-the-concurrent-mark-phase/?ref=daveabrock.com">continues his series on .NET GC internals</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/common-files-dotnet-solution?ref=daveabrock.com">writes about common files in a .NET solution</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/winui-3-misconceptions/?ref=daveabrock.com">writes about WinUI 3.0 misconceptions</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Richard Seroter <a href="https://seroter.com/2021/02/03/lets-compare-the-cloud-shells-offered-by-aws-microsoft-azure-and-google-cloud-platform/?ref=daveabrock.com">compares cloud shells across the various cloud providers</a>.</li><li>The Azure SDK folks <a href="https://devblogs.microsoft.com/azure-sdk/state-of-the-azure-sdk-2021?ref=daveabrock.com">write about the state of the SDK</a>.</li><li>ErikEJ <a href="https://erikej.github.io/sqlserver/2021/02/01/azure-sql-advanced-deployment-part4.html?ref=daveabrock.com">finishes his series on advanced automated deployments of Azure SQL with Azure DevOps</a>.</li><li>Jonathan George <a href="https://endjin.com/blog/2021/02/configuration-in-azure-functions-part-1-whats-in-the-box.html?ref=daveabrock.com">writes about configuration in Azure Functions</a>.</li><li>Leonard Lobel <a href="https://lennilobel.wordpress.com/2020/10/04/transactions-in-azure-cosmos-db-with-the-net-sdk/?ref=daveabrock.com">works with transactions in Azure Cosmos DB with the .NET SDK</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Michael Shpilt <a href="https://michaelscodingspot.com/what-i-learned-about-c-from-job-interviews/?ref=daveabrock.com">writes about what he learned about C# from job interviews</a>.</li><li>Szymon Kulec <a href="https://blog.scooletz.com/2021/02/03/spans-memory-mental-model?ref=daveabrock.com">writes about his mental model of Span, Memory, and ReadOnlySequence in .NET</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/include-il-offset-into-production-exception-stack-traces/?ref=daveabrock.com">includes IL offsets into production exception stack traces</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations?ref=daveabrock.com">writes about using declarations in C# 8</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Paul Vick <a href="https://devblogs.microsoft.com/visualstudio/working-with-large-net-5-solutions-in-visual-studio-2019-16-8?ref=daveabrock.com">writes about recent Visual Studio improvements that help with working with large .NET 5 solutions</a>.</li><li>Huang Qiangxiong <a href="https://grpc.io/blog/wireshark/?ref=daveabrock.com">analyzes gRPC messages with Wireshark</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/if-you-code-on-windows-you-deserve-a-better-terminal-94e52014d848?ref=daveabrock.com">writes about the new Windows Terminal</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Feb/04/Opening-an-Admin-Windows-Terminal-from-Visual-Studio?ref=daveabrock.com">opens an admin Windows Terminal from Visual Studio</a>.</li><li>Lee Richardson <a href="http://www.leerichardson.com/2021/02/he-one-thing-i-wish-id-known-before.html?ref=daveabrock.com">looks back on lessons learned when using Cake</a>.</li><li>Matt Lacey <a href="https://www.mrlacey.com/2021/02/here-i-made-this-to-search.html?ref=daveabrock.com">updates his VS extension to search Stack Overflow</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/29/vs-code-tips.aspx?ref=daveabrock.com">writes about tips for working with VS Code</a>.</li><li>Johnny Reilly <a href="https://blog.johnnyreilly.com/2021/01/aspnet-serilog-and-application-insights.html?ref=daveabrock.com">works with ASP.NET, Serilog, and Application Insights</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Steven Thewissen <a href="https://www.thewissen.io/handling-the-new-uidatepicker-in-xamarin-forms/?ref=daveabrock.com">handles the new UIDatePicker</a>.</li><li>James Montemagno <a href="https://devblogs.microsoft.com/xamarin/beautiful-custom-radiobutton-with-xamarin-forms-5?ref=daveabrock.com">creates a RadioButton control</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The .NET Rocks show <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1725&ref=daveabrock.com">talks to Jeff Fritz about Blazor Static Web App</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-181-marten-db-with-jeremy-d-miller/?ref=daveabrock.com">talks to Jeremy D. Miller about Marten DB</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-054-how-do-you-develop-an-ide-jetbrains-rider-with-maarten-balliauw/?ref=daveabrock.com">talks to Maarten Balliauw about developing an IDE</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/239?ref=daveabrock.com">talks about planning an app release</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>The ON.NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Building-real-applications-with-Orleans?ref=daveabrock.com">talks with Reuben Bond about Orleans</a>, <a href="https://www.youtube.com/watch?v=da9u5tqw-eo&ref=daveabrock.com">deploys Orleans apps to Kubernetes</a>, and <a href="https://www.youtube.com/watch?v=HVI7l9qgum4&ref=daveabrock.com">runs PHP and WordPress sites on .NET with PeachPie</a>.</li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/Xamarin-Community-Toolkit-TabView?ref=daveabrock.com">walks through the Xamarin Community Toolkit</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ How to nuke sensitive commits from your GitHub repository ]]></title>
        <description><![CDATA[ Let&#39;s learn how to hit Ctrl+Z on a regretful commit. ]]></description>
        <link>https://www.daveabrock.com/2021/02/09/nuke-sensitive-commits-from-github/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 08 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1597451773417-891ce13364ab?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDR8fG51a2V8ZW58MHx8fHwxNjE5ODMyODI4&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>We all make mistakes. Let’s talk about one of my recent ones.</p><p>I created a GitHub repository that tweets old posts of mine, which was heavily stolen inspired by <a href="https://khalidabuhakmeh.com/automate-your-blog-with-github-actions?ref=daveabrock.com">Khalid Abuhakmeh’s solution</a>. (Yes, the repo <a href="https://github.com/daveabrock/TweetOldPosts?ref=daveabrock.com">is called TweetOldPosts</a>.) It is scheduled through <a href="https://github.com/daveabrock/TweetOldPosts/blob/master/.github/workflows/main.yml?ref=daveabrock.com">a GitHub Action</a>.</p><p>To connect to the <a href="https://github.com/linvi/tweetinvi?ref=daveabrock.com">Tweetinvi API</a>, I had to pass along a consumer key, consumer secret, access token, and access token secret. Like a responsible developer, I stored these as <a href="https://docs.github.com/en/actions/reference/encrypted-secrets?ref=daveabrock.com">encrypted secrets in GitHub</a>. Before I did that, though, I hardcoded these values to <em>get it working</em>. I pushed these changes to GitHub. Oops.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daveabrock.com/content/images/2021/05/github-secrets-bad.jpg" class="kg-image" alt="My bad commit" loading="lazy" width="242" height="140"><figcaption>Mistakes were made.</figcaption></figure><p>After refreshing the keys—which you should do immediately, should you find yourself in the same situation— I was wondering how I could pretend this never happened. This post shows you how to delete files with sensitive data from your commit history.</p><p>To resolve this issue, you could use <code>filter-branch</code>, if the <a href="https://git-scm.com/docs/git-filter-branch?ref=daveabrock.com">warning in the documentation</a> doesn’t scare you:</p><blockquote>git filter-branch has a plethora of pitfalls that can produce non-obvious manglings of the intended history rewrite (and can leave you with little time to investigate such problems since it has such abysmal performance). These safety and performance issues cannot be backward compatibly fixed and as such, its use is not recommended. Please use an alternative history filtering tool such as git filter-repo. If you still need to use git filter-branch, please carefully read SAFETY (and PERFORMANCE) to learn about the land mines of filter-branch, and then vigilantly avoid as many of the hazards listed there as reasonably possible.</blockquote><p>Eek. Scary. Luckily, there’s a simpler and faster alternative: the <a href="https://rtyley.github.io/bfg-repo-cleaner/?ref=daveabrock.com">open-source BFG Repo Cleaner</a>. I wanted something quick and simple, because this is the only time I’ll need to do this. Stop laughing.</p><h2 id="remove-appsettings-json-from-commit-history">Remove appsettings.json from commit history</h2><p>As for me, I accidentally pushed an <code>appsettings.json</code> file. I don’t need that file at all. So, for me, once I <a href="https://repo1.maven.org/maven2/com/madgag/bfg/1.13.2/bfg-1.13.2.jar?ref=daveabrock.com">downloaded the BFG JAR file</a>, my task was pretty simple.</p><p>Here’s what to do:</p><p>Clone a fresh copy of your impacted repository with the <code>--mirror</code> flag, like this:</p><pre><code>git clone --mirror https://github.com/{user}/{repo}.git
</code></pre><p>The <code>--mirror</code> flag clones a bare repository, which is a full copy of your Git database—but it contains no working files. If you’ve ever looked into a <code>.git</code> folder, it’ll look familiar. <strong>Make sure you create a backup of this repository.</strong></p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/bare.jpg" class="kg-image" alt="My bare repo" loading="lazy" width="627" height="279" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/bare.jpg 600w, https://www.daveabrock.com/content/images/2021/05/bare.jpg 627w"></figure><p>Assuming you have the Java runtime installed, run the following command. (You can also set an alias for <code>java -jar bfg.jar</code> to just call <code>bfg</code>.) This deletes the file from your history (but not the current version, although I don’t care).</p><pre><code>java -jar bfg.jar --delete-files appsettings.json
</code></pre><p>With this command, BFG cleans my commits and branches to remove <code>appsettings.json</code>.</p><p>Here’s the response I get back:</p><pre><code> Using repo : C:\code\TweetOldPosts.git

 Found 8 objects to protect
 Found 2 commit-pointing refs : HEAD, refs/heads/master

 Protected commits
 -----------------

 These are your protected commits, and so their contents will NOT be altered:

 * commit xxxxxxxx (protected by 'HEAD')

 Cleaning
 --------

 Found 17 commits
 Cleaning commits:       100% (17/17)
 Cleaning commits completed in 182 ms.

 Updating 1 Ref
 --------------

         Ref                 Before     After
         ---------------------------------------
         refs/heads/master | xxxxxxxx | xxxxxxxx

 Updating references:    100% (1/1)
 ...Ref update completed in 14 ms.

 Commit Tree-Dirt History
 ------------------------

         Earliest      Latest
         |                  |
         .Dm Dmmmmm mmmmm mmm

         D = dirty commits (file tree fixed)
         m = modified commits (commit message or parents changed)
         . = clean commits (no changes to file tree)

                                 Before     After
         -------------------------------------------
         First modified commit | xxxxxxxx | xxxxxxxx
         Last dirty commit     | xxxxxxxx | xxxxxxxx

 Deleted files
 -------------

         Filename           Git id
         -----------------------------------
         appsettings.json | xxxxxxxx (308 B)


 In total, 20 object ids were changed. Full details are logged here:

         C:\code\TweetOldPosts.git.bfg-report\2021-02-09\21-26-32
</code></pre><p>While the Git data is updated, nothing has been deleted yet. After you confirm the repo is updated correctly, run the following two commands to do so. <strong>Again, make sure you have a backup.</strong></p><pre><code> git reflog expire --expire=now --all
 git gc --prune=now --aggressive
</code></pre><p>Finally, do a <code>git push</code> to push your changes up to GitHub. My file is no longer in my commit history. You’re ready to do a fresh <code>git clone</code> and pretend that it never happened (unless you decided to write about it).</p><h2 id="resources">Resources</h2><ul><li><a href="https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository?ref=daveabrock.com">Removing sensitive data from a repository</a> (GitHub)</li><li><a href="https://rtyley.github.io/bfg-repo-cleaner/?ref=daveabrock.com">BFG Repo-Cleaner Docs</a></li><li><a href="https://github.com/rtyley/bfg-repo-cleaner?ref=daveabrock.com">BFG Repo-Cleaner Repo</a></li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #35: 🔑 Nothing is certain but death and expiring certificates ]]></title>
        <description><![CDATA[ This week, we talk about NuGet, Razor improvements, and more. ]]></description>
        <link>https://www.daveabrock.com/2021/02/06/dotnet-stacks-35/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe8a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 05 Feb 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-11.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to another week, everybody. I’ve been getting some complaints; I haven’t had a bad joke in a while. I know it’d be a nice shot in the arm, but now’s not the time to be humerus.</p><p>We’re covering a lot of little things this week, so let’s get started.</p><hr><p>This week, the .NET team announced improvements to the new Razor editor in Visual Studio (obviously in response to <a href="https://daveabrock.com/2021/01/30/dotnet-stacks-34?ref=daveabrock.com">my complaints last week</a>).</p><p>Six months ago, the team <a href="https://devblogs.microsoft.com/aspnet/improvements-to-the-new-razor-editor-in-visual-studio/?ref=daveabrock.com">announced a preview of an experimental Razor editor</a> based on a common Razor language server. (We <a href="https://daveabrock.com/2020/07/25/dotnet-stacks-9?ref=daveabrock.com">talked about it in Issue #9</a>, if you want all the specifics.) It’s now available in the latest Visual Studio preview (<a href="https://visualstudio.com/preview?ref=daveabrock.com">16.9 version 3</a>).</p><p>The new Razor editor allows the team to enable C# code actions more easily—with this update, Razor can help you discover using statements and null checks. This also extends to Blazor. Check out the <a href="https://devblogs.microsoft.com/aspnet/improvements-to-the-new-razor-editor-in-visual-studio/?ref=daveabrock.com">blog post</a> for details (and you can fill out a survey <a href="https://www.surveymonkey.com/r/LFYCKPN?ref=daveabrock.com">about syntax coloring</a>.)</p><hr><p>The NuGet team needed some #HugOps this week as they <a href="https://visualstudiomagazine.com/articles/2021/01/27/nuget-issue.aspx?ref=daveabrock.com">dealt with an expired certificate</a> that temporarily broke .NET 5 projects running on Debian Linux.</p><p>Here’s what the <a href="https://github.com/NuGet/Announcements/issues/49?ref=daveabrock.com">NuGet team had to say</a>:</p><blockquote>This is because of an issue reported in the ca-certificates package in which the root CA being used are not trusted and must be installed manually due to Symantec Issues. Debian removed the impacted Symantec certificate from their ca-certificates package in buster (Debian 10) impacting all user … The Debian patch was too broad in removing the certificate for all uses and created the error messages seen today.</blockquote><p>For some good news, the NuGet website has a new <em>Open in FuGet Package Explorer</em> link that allows you to <a href="https://twitter.com/JamesMontemagno/status/1355231390967721985?ref=daveabrock.com">explore packages with FuGet</a>.</p><hr><p>This week, I <a href="https://daveabrock.com/2021/01/26/signed-http-exchanges-cdn-cache?ref=daveabrock.com">wrote about Signed HTTP Exchanges</a>. In our interview <a href="https://daveabrock.com/2021/01/17/dev-discussions-steve-sanderson?ref=daveabrock.com">with Blazor creator Steve Sanderson</a>, he mentioned it as a way to potentially help speed up runtime loading for Blazor WebAssembly applications by using it as a type of cross-site CDN cache.</p><p>Here’s what he told us:</p><blockquote>It’s conceivable that new web platform features like Signed HTTP Exchanges could let us smartly pre-load the .NET WebAssembly runtime in a browser in the background (directly from some Microsoft CDN) while you’re visiting a Blazor WebAssembly site, so that it’s instantly available at zero download size when you go to other Blazor WebAssembly sites. Signed HTTP Exchanges allow for a modern equivalent to the older idea of a cross-site CDN cache. We don’t have a definite plan about that yet as not all browsers have added support for it.</blockquote><p>It isn’t a sure thing because the technology is still quite new, but it’s a promising idea to overcome the largest drawback of using Blazor WebAssembly.</p><hr><p>I’ve written about <a href="https://daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm?ref=daveabrock.com">prerendering Blazor WebAssembly apps</a>. It’s a little weird, as you give up the ability to host your app as static files. Why not host over Blazor Server, then?</p><p>This week, Andrew Lock <a href="https://andrewlock.net/prerending-a-blazor-webassembly-app-without-an-asp-net-core-host-app/?ref=daveabrock.com">wrote about a creative approach</a> where you can prerender an app to static files without a host app. It does have tradeoffs—you need to define routes beforehand and it doesn’t work well if you’re working with dynamic data—but it’s worth checking out if it fits your use case.</p><hr><p>At the Entity Framework <a href="https://www.youtube.com/watch?v=lmHU1zD2mvA&ref=daveabrock.com">community standup this week</a>, they discussed the <code>MSBuild.Sdk.SqlProj</code> project with Jonathan Mezach. Already <a href="https://github.com/rr-wfm/MSBuild.Sdk.SqlProj?ref=daveabrock.com">sitting at 42k downloads from GitHub</a>, it’s an SDK that produces <em>.dacpac</em> files from SQL scripts that can be deployed using <code>SqlPackage.exe</code> or <code>dotnet publish</code>. It’s like SQL Server Data Tools but built with the latest tooling.</p><p>You can check out Jonathan’s <a href="https://jmezach.github.io/post/introducing-msbuild-sdk-sqlproj/?ref=daveabrock.com">announcement on his blog</a> to understand how it all works and his motivations for building it.</p><hr><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Daniel Roth <a href="https://devblogs.microsoft.com/aspnet/improvements-to-the-new-razor-editor-in-visual-studio?ref=daveabrock.com">writes about improvements to the new Razor editor in Visual Studio</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/prerending-a-blazor-webassembly-app-without-an-asp-net-core-host-app/?ref=daveabrock.com">prerenders a Blazor WebAssembly app to static files without an ASP.NET host app</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/choosing-a-servicelifetime/?ref=daveabrock.com">writes how to choose a ServiceLifetime</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>Kayla Cinnamon <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-6-release?ref=daveabrock.com">announces Windows Terminal Preview 1.6</a>.</li><li>Mads Kristensen <a href="https://devblogs.microsoft.com/visualstudio/new-experience-for-sending-us-your-feedback?ref=daveabrock.com">writes about new ways to provide Visual Studio feedback</a>.</li><li>Gerald Versluis <a href="https://devblogs.microsoft.com/xamarin/xamarin-community-toolkit?ref=daveabrock.com">introduces the Xamarin Community Toolkit</a>.</li><li>PostSharp introduces <a href="https://blog.postsharp.net/post/announcing-caravela-preview.html?ref=daveabrock.com">Project Caravela, a Roslyn-based aspect framework</a>.</li><li>W3C welcomes <a href="https://www.w3.org/blog/2021/01/welcome-to-open-web-docs/?ref=daveabrock.com">Open Web Docs</a>, while <a href="https://blogs.windows.com/msedgedev/2021/01/25/welcome-open-web-docs?ref=daveabrock.com">Microsoft</a> and <a href="https://hacks.mozilla.org/2021/01/welcoming-open-web-docs-to-the-mdn-family/?ref=daveabrock.com">Mozilla</a> also write about it.</li><li>As David Ramel writes, <a href="https://visualstudiomagazine.com/articles/2021/01/22/github-enterprise-server.aspx?ref=daveabrock.com">GitHub ships Enterprise Server 3.0 Release Candidate</a>.</li><li>In JetBrains news, Matthias Koch <a href="https://blog.jetbrains.com/dotnet/2021/01/25/rider-2021-1-roadmap/?ref=daveabrock.com">writes about the Rider 2021.1 roadmap</a>, Matt Ellis <a href="https://blog.jetbrains.com/dotnet/2021/01/27/resharper-2021-1-roadmap/?ref=daveabrock.com">provides a ReSharper 2021.1 roadmap</a>, and Friedrich von Never has an <a href="https://twitter.com/fvnever/status/1354092934073872385?ref=daveabrock.com">interesting Twitter thread</a> about how they debug Blazor WebAssembly. .</li><li>David McCarter <a href="https://www.c-sharpcorner.com/article/coding-faster-with-the-dotnettips-utility-february-2021-update/?ref=daveabrock.com">updates his dotNetTips utility</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>For the community standups, ASP.NET <a href="https://www.youtube.com/watch?v=_znjce8Cs2k&ref=daveabrock.com">talks about better Razor editing in Visual Studio</a> and Entity Framework <a href="https://www.youtube.com/watch?v=lmHU1zD2mvA&ref=daveabrock.com">introduces MsBuild.Sdk.SqlProj</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=TCnPdRxWDj4&ref=daveabrock.com">talks about creating an OSS mobile app with Xamarin and Azure</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Dave Brock <a href="https://daveabrock.com/2021/01/26/signed-http-exchanges-cdn-cache?ref=daveabrock.com">writes about using Signed HTTP Exchanges to help with runtime loading in Blazor WebAssembly</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/using-roles-in-blazor-webassembly-hosted-applications/?ref=daveabrock.com">uses roles in Blazor Web Assembly hosted applications</a>.</li><li>Jeetendra Gund <a href="https://www.telerik.com/blogs/select-tag-helper-asp-net-core-mvc?ref=daveabrock.com">uses the Select tag helper in ASP.NET Core MVC</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/authentication-in-blazor-webassembly-hosted-applications/?ref=daveabrock.com">writes about authentication in Blazor WebAssembly hosted application</a>.</li><li>Changhui Xu <a href="https://codeburst.io/uploading-multiple-files-with-angular-and-net-web-api-7560303d9345?ref=daveabrock.com">writes about uploading multiple files with Angular and ASP.NET Web API</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/01/25/grpc-asp-net-core-5-add-a-grpc-service-reference-from-a-remote-protobuf-over-route-to-code/?ref=daveabrock.com">adds a gRPC service reference from a remote protobuf over Route-To-Code</a>.</li></ul><h3 id="-the-net-platform">🥅 The .NET platform</h3><ul><li>Konrad Kokosa <a href="https://tooslowexception.com/net-gc-internals-the-mark-phase/?ref=daveabrock.com">continues writing about .NET GC internals</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/create-dotnet-project-template/?ref=daveabrock.com">creates a .NET project template</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Ryan Palmer <a href="https://www.compositional-it.com/news-blog/automated-database-deployment-with-azure-and-farmer/?ref=daveabrock.com">automates database deployments with Azure and Farmer</a>.</li><li>Peter De Tender <a href="https://devblogs.microsoft.com/devops/demystifying-service-principals-managed-identities?ref=daveabrock.com">demystifies service principals and managed identities</a>.</li><li>Shelton Graves <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/event-driven-on-azure-part-1-why-you-should-consider-an-event/ba-p/2106983?ref=daveabrock.com">writes about choosing an event-driven architecture</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/01/28/implement-oauth-device-code-flow-with-azure-ad-and-asp-net-core/?ref=daveabrock.com">implements an OAuth device code flow with Azure AD and ASP.NET Core</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-ASP-NET-Core-API-Integration-With-Azure-Service-Bus-Queue/?ref=daveabrock.com">builds out his ASP.NET Core API with an Azure Service Bus</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Jon Skeet <a href="https://codeblog.jonskeet.uk/2021/01/27/osc-mixer-control-in-c?ref=daveabrock.com">writes an OSC mixer control in C#</a>.</li><li>Luca Bolognese <a href="https://devblogs.microsoft.com/dotnet/using-c-source-generators-to-create-an-external-dsl?ref=daveabrock.com">uses C# source generators to create an external DSL</a>.</li><li>Karthik Chintala <a href="https://coderethinked.com/observer-design-pattern-with-an-example-in-csharp/?ref=daveabrock.com">writes about the Observer design pattern</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/dotnet-5-source-generators-jump-start?ref=daveabrock.com">gets you started with .NET 5 source generators</a>.</li><li>Jason Roberts <a href="http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Switch-Expressions?ref=daveabrock.com">writes about switch expressions</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/using-valuetask-to-create-methods-that-can-work-as-sync-or-async/?ref=daveabrock.com">uses ValueTask to create methods that work as sync or async</a>.</li><li>Matthew Crews <a href="https://matthewcrews.com/blog/2021/01/2021-01-25/?ref=daveabrock.com">writes about scheduling jobs in F# for maximum efficiency</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Jan/26/Chromium-WebView2-Control-and-NET-to-JavaScript-Interop-Part-2?ref=daveabrock.com">continues writing about the Chromium WebView2 control and .NET</a>.</li><li>Elton Stoneman <a href="https://blog.sixeyed.com/build-docker-images-quickly-with-github-actions-and-a-self-hosted-runner/?ref=daveabrock.com">builds Docker images quickly with GitHub Actions and a self-hosted runner</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/how-to-update-a-databases-schema-without-using-ef-cores-migrate-feature/?ref=daveabrock.com">updates a database schema without using EF Core’s migrate feature</a>.</li><li>ErikEJ <a href="https://erikej.github.io/sqlserver/2021/01/25/azure-sql-advanced-deployment-part3.html?ref=daveabrock.com">writes about advanced automated deployments of an Azure SQL database with Azure DevOps</a>.</li><li>Dane Vinson <a href="https://developingdane.azurewebsites.net/jsonenvelopes/?ref=daveabrock.com">writes about the JsonEnvelopes library that helps serialize and deserialize message receivers</a>.</li><li>Microsoft announces <a href="https://devblogs.microsoft.com/cppblog/windows-arm64-support-for-cmake-projects-in-visual-studio?ref=daveabrock.com">Windows ARM64 support for CMake projects in Visual Studio</a>.</li><li>Mark-James McDougall <a href="https://markjames.dev/2021-01-23-plotting-csv-files-fsharp/?ref=daveabrock.com">plots graphs from CSV files in F# using XPlot</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Leomaris Reyes <a href="https://www.syncfusion.com/blogs/post/replicating-talent-casting-ui-in-xamarin-forms.aspx?ref=daveabrock.com">replicates a talent casting UI</a>.</li><li>The Xamarin Show <a href="https://channel9.msdn.com/Shows/XamarinShow/Introducing-the-Xamarin-Community-Toolkit?ref=daveabrock.com">discusses the Xamarin Community Toolkit</a>.</li><li>Luis Matos warns: <a href="https://luismts.com/dont-use-collectionview-inside-scrollview/?ref=daveabrock.com">don’t use CollectionView inside ScrollView in Xamarin.Forms</a>.</li></ul><h3 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h3><ul><li>Stephen Cleary <a href="https://blog.stephencleary.com/2021/01/asynchronous-messaging-4-retrieve-results.html?ref=daveabrock.com">writes about retrieving results from async messaging</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/avoiding-a-big-ball-of-mud/?ref=daveabrock.com">writes about avoiding a big ball of mud</a>.</li><li>Changhui Xu <a href="https://codeburst.io/integration-tests-for-asp-net-core-web-apis-using-mstest-f4e222a3bc8a?ref=daveabrock.com">writes integration tests for ASP.NET Core Web APIs using MSTest</a>.</li><li>Piotr Martyniuk <a href="https://www.cncf.io/blog/2021/01/22/how-to-connect-microservices-part-1-types-of-communication/?ref=daveabrock.com">writes about connecting microservices</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1724&ref=daveabrock.com">talks to Julie Lerman about .NET 5</a>.</li><li>On Yet Another Podcast, <a href="http://jesseliberty.com/2021/01/26/mads-torgersen-c-9-beyond?ref=daveabrock.com">Jesse Liberty talks C# with Mads Torgersen</a>.</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-053-abusing-c-calendars-epochs-and-the-net-functions-framework-with-jon-skeet-part-2/?ref=daveabrock.com">continues talking with Jon Skeet</a>.</li><li>The .NET Core Show <a href="https://dotnetcore.show/episode-68-xamarin-catch-up-with-luce-carter/?ref=daveabrock.com">talks about Xamarin with Luce Carter</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>The ON.NET Show <a href="https://www.youtube.com/watch?v=QuXI4rPaczc&ref=daveabrock.com">talks about using Azure AD B2C for authenticating users</a>, and also <a href="https://www.youtube.com/watch?v=jIT8r2r5kV8&ref=daveabrock.com">about distributed applications with ZeroMQ</a>.</li><li>Jeremy Likness and Abel Wang <a href="https://channel9.msdn.com/Shows/On-NET/DevOps-for-ASPNET-Developers-Hosting-NuGet-Packages?ref=daveabrock.com">talk about hosting NuGet packages</a>.</li><li>Brigit Murtaugh <a href="https://channel9.msdn.com/Series/Beginners-Series-to-Dev-Containers/Introduction-1-of-8--Beginners-Series-to-Dev-Containers?ref=daveabrock.com">starts a beginner’s series on dev containers</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2021/01/25/DustinCampbellOnSupportForWinFormsToTheVisualStudioDesigner.aspx?ref=daveabrock.com">David Giard talks with Dustin Campbell about WinForms support for Visual Studio Designer</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ How to achieve style inheritance with Blazor CSS isolation ]]></title>
        <description><![CDATA[ We explore how to achieve traditional style inheritance with Blazor CSS isolation. ]]></description>
        <link>https://www.daveabrock.com/2021/01/31/blazor-css-iso-inheritance-scopes/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe89</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 30 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1610986603166-f78428624e76?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDE4fHxjc3N8ZW58MHx8fHwxNjE5ODMyOTI2&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Are you familiar with Blazor CSS isolation? Last year, when it was released, I <a href="https://daveabrock.com/2020/09/10/blazor-css-isolation?ref=daveabrock.com">wrote an introductory post</a> and the <a href="https://docs.microsoft.com/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0&ref=daveabrock.com">official ASP.NET Core doc</a>. If you want a quick primer, here goes: Blazor CSS isolation allows you to scope styles to a specific component. With CSS isolation, you can package your styles to your components, and you also don’t need to worry about the inevitable headaches when working with vendor styles and global CSS.</p><p>As I’ve spoken to a few user groups about CSS isolation, I always get the same question: <em>how can I use this to inherit styles between components</em>? Good question. This post will show you how.</p><p>When I say <em>inherit styles</em>, I’m <em>not</em> referring to how you can <a href="https://daveabrock.com/2020/09/10/blazor-css-isolation?ref=daveabrock.com#how-to-work-with-child-components">pass the same styles down to child components</a>, such as when you want all of a component’s children to have the same <code>h1</code> style declaration. I’m referring to when you want a base set of styles shared across a set of components. You might be doing this without CSS isolation. For example, if you define most of your styles using a library like Bootstrap, you lean on the library for most of your styles—then you have a custom stylesheet (like <code>custom.css</code>) that overrides those when appropriate.</p><p>If we’re honest, with Blazor CSS isolation, the “C” (cascading) is non-existent. There’s no cascading going on here—isolating your styles is the opposite of cascading. With Blazor CSS isolation, you scope your CSS component styles. Then, at build time, Blazor takes care of the cascading for you. When you wish to inherit styles and share them between components, you’re losing many of the advantages of using scoped CSS.</p><p>In my opinion, using inheritance with CSS isolation <strong>works best when you want to share styles across a small group of similar components</strong>. If you have 500 components in your solution and you want to have base styles across them all, you may be creating more problems for yourself. In those cases, you should stick with your existing tools.</p><p>With that knowledge in place, let’s understand how to use inheritance with Blazor CSS isolation.</p><h2 id="inherit-styles-using-css-isolation">Inherit styles using CSS isolation</h2><p>I’m using a newly created Blazor WebAssembly app (it’ll work for Blazor Server, too). If you’ve worked with Blazor, it’s from the template with <code>Index</code>, <code>Counter</code>, and <code>FetchData</code> components. To create an app, run this from the <code>dotnet</code> CLI and run it to confirm it works:</p><pre><code>dotnet new blazorwasm -o "CSSIsoInheritance"
cd blazorwasm
dotnet run
</code></pre><p>In your <code>Pages</code> folder, create the following files:</p><ul><li><code>BaseComponent.razor</code></li><li><code>BaseComponent.razor.css</code></li><li><code>FetchData.razor.css</code></li><li><code>Counter.razor.css</code></li></ul><p>In <code>BaseComponent.razor.css</code> we’ll share an <code>h1</code> and <code>p</code> style across your components.</p><pre><code class="language-css">h1 {
    color: red;
}

p {
    text-decoration-line: underline;
}
</code></pre><h2 id="your-key-to-inheritance-scope-identifiers">Your key to inheritance: scope identifiers</h2><p>As mentioned previously, Blazor CSS isolation is a compile-time, file-based solution. Out of the box, it’ll look for a <code>MyComponent.razor.css</code> file that matches a <code>MyComponent.razor</code> file. At compile time, it’ll assign a scope identifier to your elements. It’s assigned for you and looks like this (your identifier will differ):</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/scoped-css.png" class="kg-image" alt="A lot of unused styles" loading="lazy" width="777" height="503" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/scoped-css.png 600w, https://www.daveabrock.com/content/images/2021/05/scoped-css.png 777w" sizes="(min-width: 720px) 720px"></figure><p>You can’t expect the solution to know about inherited classes. I say this repeatedly because it’s important: <em>Blazor CSS isolation is a file-based solution</em>. To accomplish inheritance, you apply a custom scope identifier across your impacted components. From your project file, you can add the following <code>&lt;ItemGroup&gt;</code>:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;None Update="Pages/BaseComponent.razor.css" CssScope="inherit-scope" /&gt;
    &lt;None Update="Pages/Counter.razor.css" CssScope="inherit-scope" /&gt;
    &lt;None Update="Pages/FetchData.razor.css" CssScope="inherit-scope" /&gt;
&lt;/ItemGroup&gt;
</code></pre><p>To save some lines, you can also use the wildcard <code>*</code> operator to include any files that end with <code>razor.css</code>:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;None Update="Pages/*.razor.css" CssScope="inherit-scope" /&gt;
&lt;/ItemGroup&gt;
</code></pre><p>If you browse to the <code>Counter</code> and <code>FetchData</code> components, you’ll see the styles are applied. Here’s how the <code>Counter</code> component looks.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/counter-inherit.png" class="kg-image" alt="The inheritance works" loading="lazy" width="728" height="393" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/counter-inherit.png 600w, https://www.daveabrock.com/content/images/2021/05/counter-inherit.png 728w" sizes="(min-width: 720px) 720px"></figure><p>If you open your Developer Tools, you’ll see the scope identifier is applied correctly. If you’re wondering, the <code>b-lib7l0qa43</code> identifier belongs to the <code>MainLayout.razor</code> file.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/inherit-scope.jpg" class="kg-image" alt="The inheritance works" loading="lazy" width="721" height="181" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/inherit-scope.jpg 600w, https://www.daveabrock.com/content/images/2021/05/inherit-scope.jpg 721w" sizes="(min-width: 720px) 720px"></figure><p>Since we didn’t apply a custom scope identifier to our <code>Index</code> component, it’s left alone.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/hey-world.jpg" class="kg-image" alt="The inheritance works" loading="lazy" width="853" height="344" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/hey-world.jpg 600w, https://www.daveabrock.com/content/images/2021/05/hey-world.jpg 853w" sizes="(min-width: 720px) 720px"></figure><h2 id="solution-drawbacks">Solution drawbacks</h2><p>As I mentioned before, you should do this carefully and cautiously, so you don’t introduce more headaches. Aside from that, the solution isn’t elegant, because:</p><ul><li>Every derived component <strong>must</strong> have a <code>razor.css</code> file, even if it’s empty</li><li>In our case (and in many cases), the base component markup is empty</li><li>You need to explicitly assign an identifier in your project file (or name impacted components similarly)</li></ul><p>Out of the box, the solution is meant for you to isolate and not share styles. However, if this fits your use case and makes sense to you, you can use this to lower your maintenance costs.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we talked about how to use inheritance with CSS isolation. We talked about how to implement inheritance as well as the benefits and drawbacks. As always, feel free to share your experiences in the comments, and check out the references below for more details on Blazor CSS isolation.</p><ul><li><a href="https://daveabrock.com/2020/09/10/blazor-css-isolation?ref=daveabrock.com">Use CSS isolation in your Blazor projects</a> (Me)</li><li><a href="https://docs.microsoft.com/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0&ref=daveabrock.com">ASP.NET Core Blazor CSS isolation</a> (ASP.NET Core Docs)</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #34: 🎙 Visual Studio gets an update, and you get a rant ]]></title>
        <description><![CDATA[ This week, we talk about Visual Studio, EF Core 6, and GitHub Pages. ]]></description>
        <link>https://www.daveabrock.com/2021/01/30/dotnet-stacks-34/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe88</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 29 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/bernie-stacks.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday to you all. I hope you had a good week. Put on your comfy mittens and let’s get started.</p><ul><li>Visual Studio gets an update, and you get a rant</li><li>EF Core 6 designs take shape</li><li>GitHub Pages gets more enterprise-y</li><li>A quick correction</li></ul><hr><h1 id="visual-studio-gets-an-update-and-you-get-a-rant">Visual Studio gets an update, and you get a rant</h1><p>The Visual Studio team <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-9-preview-3/?ref=daveabrock.com">has released v16.9 Preview 3</a>. This one’s a hodgepodge, but a big call out is the ability to <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-9-preview-3/?ref=daveabrock.com">view source generators from the Solution Explorer</a>. This allows you to inspect the generated code easily. People are <a href="https://twitter.com/konradkokosa/status/1352313233705676800?ref=daveabrock.com">already getting excited</a>.</p><p>Since we’re on the subject, Jerry Nixon polled some folks this week about <a href="https://twitter.com/jerrynixon/status/1351602460121567239?ref=daveabrock.com">their preferred IDE</a>. (I say VS Code is only an IDE when you install extensions, but I digress.) As of Sunday night, JetBrains Rider comes in at around 26%. It might seem low to you, but not to me. After years of Windows-only .NET making Visual Studio the only realistic IDE, it’s amazing that a third-party tool is gaining so much traction. This recognition is well-deserved, by the way—it’s fast, feature-rich, and does so much out-of-the-box that Visual Studio doesn’t. I installed it this week after thinking about it for years, and am impressed so far.</p><p>Of course, your mileage may vary and the “new and different” is always alluring at first. But, to me, what’s more troubling is my <em>reason</em> for giving it a try. I wouldn’t be offended if you called me a Visual Studio fanboy. I’ve used it for over a decade and a half. Even so: the Razor editing experience is a pain (with the admission they are rolling out a new editor), and component discovery is a hassle when working with Blazor, and closing and restarting Visual Studio is still a thing, in 2021. This is part of a general theme (<a href="https://twitter.com/ChaseAucoin/status/1352668578684796930?ref=daveabrock.com">and I’m not the only one</a>): why is Blazor tooling in Visual Studio still so subpar? I’ve found Rider to provide a better Blazor development experience. Is it antecdotal? Yes. Do I think it’s just me? No.</p><p>I know it’s being worked on, I get it, but: when you deliver a wonderful, modern library with hype that hasn’t been seen in years … how is your flagship IDE not providing a development experience to match? Whether it’s internal priorities or a million other reasons that impact a large corporation, the expectation that Visual Studio users will have to wait and deal with it is suitable when customers don’t have a choice. They do now, and a non-Microsoft tool is consistently beating them on the Blazor development experience. I’m disappointed.</p><hr><h1 id="ef-core-6-designs-take-shape">EF Core 6 designs take shape</h1><p>This week, Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/the-plan-for-entity-framework-core-6-0/?ref=daveabrock.com">shared</a> the high-level, subject-to-change <a href="https://docs.microsoft.com/ef/core/what-is-new/ef-core-6.0/plan?ref=daveabrock.com">plan for EF Core 6</a>—to be released with .NET 6 in November. It’ll target .NET 6, of course, won’t run on .NET Framework and likely will not support any flavor of .NET Standard.</p><p>Some big features make the list, like SQL Server temporal tables (allowing you to create them from migrations and the ability to access historical data), JSON columns, compiled models, and a plan to match Dapper performance. The latter definitely caught my eye. As David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/19/ef-core-plans.aspx?ref=daveabrock.com">writes this week</a>, he quotes Jeremy as saying: “This is a significant challenge which will likely not be fully achieved. Nevertheless, we will get as close as we can.”</p><p>In other EF news, the team released a <a href="https://docs.microsoft.com/ef/core/change-tracking/?ref=daveabrock.com">new doc on EF Core change tracking</a>.</p><hr><h1 id="github-pages-gets-more-enterprise-y">GitHub Pages gets more enterprise-y</h1><p>As Microsoft is trying to make sense of competing workloads with GitHub and consolidate products–we’ve talked a few times about Azure DevOps and GitHub Actions—look for things in GitHub to get a little more enterprise-<em>y</em>.</p><p>This week, GitHub released <a href="https://github.blog/changelog/2021-01-21-access-control-for-github-pages/?ref=daveabrock.com">something called</a> “Access Control for GitHub Pages”, rolled out to the GitHub Enterprise Cloud. This gives you the option to limit access of GitHub Pages to users with repository access. This is ideal for documentation and knowledge bases, or any other static site needs.</p><hr><h1 id="a-quick-correction">A quick correction</h1><p>There is no magic “undo” command with newsletters, sadly. I’d like to make a correction from last week.</p><p>I hope you enjoyed last week’s <a href="https://daveabrock.com/2021/01/17/dev-discussions-steve-sanderson?ref=daveabrock.com">interview with Steve Sanderson, the creator of Blazor</a>. I made a mistake in the introduction. Here’s what I originally wrote:</p><blockquote>It seems like forever ago when, <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">at NDC Oslo in 2017</a>, Steve Sanderson talked about a fun project he was working on, called .NET Anywhere. In the demo, he was able to load and run C# code—<em>ConsoleApp1.dll</em>, specifically—in the browser, using Web Assembly. C# in the browser! In the talk, he called it “<em>an experiment, something for you to be amused by</em>.”</blockquote><p>I made the implication that Steve created the Dot Net Anywhere (DNA) runtime. With apologies to Chris Bacon, not true!</p><p>Here’s what I <em>should</em> have said:</p><blockquote>It seems like forever ago when, <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">at NDC Oslo in 2017</a>, Steve Sanderson showed off a new web UI framework with the caveat: “<em>an experiment, something for you to be amused by</em>.” By extending <a href="https://github.com/chrisdunelm/DotNetAnywhere?ref=daveabrock.com">Dot Net Anywhere</a> (DNA), Chris Bacon’s portable .NET runtime, on WebAssembly, he was able to load and run C# in the browser. In the browser!</blockquote><p>Thanks to Steve for <a href="https://twitter.com/stevensanderson/status/1351078228971159553?ref=daveabrock.com">the clarification</a>.</p><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-4">🔥 The Top 4</h2><ul><li>Andrew Lock <a href="https://andrewlock.net/enabling-prerendering-for-blazor-webassembly-apps/?ref=daveabrock.com">enables prerendering for Blazor WebAssembly apps</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-ASP-NET-Core-API-Integration-With-Azure-Storage-Accont/?ref=daveabrock.com">integrates an Azure Storage Account with his API project</a>.</li><li>Iris Classon <a href="https://www.irisclasson.com/2021/01/20/get-azstorageaccount-your-azure-credentials-have-not-been-set-up-or-have-expired/?ref=daveabrock.com">deals with Azure credentials issues</a>.</li><li>Neils Swimberghe <a href="https://swimburger.net/blog/dotnet/use-yarp-to-host-client-and-api-server-on-a-single-origin?ref=daveabrock.com">uses YARP to host a client and API server on a single origin to avoid CORS</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>The Azure SDK team <a href="https://devblogs.microsoft.com/azure-sdk/january-2021-release?ref=daveabrock.com">has shipped their January release</a>.</li><li>Jacqueline Widdis <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-9-preview-3?ref=daveabrock.com">announces Visual Studio 2019 v16.9 Preview 3</a>.</li><li>Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/the-plan-for-entity-framework-core-6-0?ref=daveabrock.com">writes about the plan for EF Core 6</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>In .NET community standups: Machine Learning <a href="https://www.youtube.com/watch?v=i3xjS5Kj9rU&ref=daveabrock.com">talks about FSharp.Stats</a>, and ASP.NET <a href="https://www.youtube.com/watch?v=x_AXKLfG8o0&ref=daveabrock.com">continues talking architecture with David Fowler</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=mIo_HTz2viI&ref=daveabrock.com">talks to Jason Bock about source generators</a>.</li><li>Neil MacMullen <a href="https://neil-macmullen.medium.com/introducing-textrude-using-scriban-to-generate-code-from-data-dad38b280076?ref=daveabrock.com">introduces Textrude for generating code from data</a>.</li><li>Sébastien Ros is at it again, releasing a <a href="https://twitter.com/sebastienros/status/1351326122915467264?ref=daveabrock.com">fast parser combinator library called Parlot</a>.</li><li>Paul Krill <a href="https://www.infoworld.com/article/3604055/net-nanoframework-taps-c-for-embedded-systems.html?ref=daveabrock.com">writes about a new nanoFramework project</a>.</li><li>There’s a .NET Conf on February 25, <a href="https://focus.dotnetconf.net/?ref=daveabrock.com">focused on Windows development</a>.</li><li>Konrad Kokosa <a href="https://tooslowexception.com/net-gc-internals-mini-series/?ref=daveabrock.com">is making a mini-series on .NET GC internals</a>.</li><li>Gregor Suttie and Richard Hooper <a href="https://gregorsuttie.com/2021/01/20/aks-zero-to-hero-series-for-everyone/?ref=daveabrock.com">are starting an AKS Zero to Hero series</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/21/radzen-open-source.aspx?ref=daveabrock.com">writes how Radzen has open-sourced a ton of their Blazor components</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/617/building-and-auto-deploying-an-aspnet-core-application-part-1-introduction?ref=daveabrock.com">builds an auto-deploys an ASP.NET Core app</a>.</li><li>Muhammed Saleem <a href="https://code-maze.com/deploying-blazor-webassembly-into-azure-static-web-apps/?ref=daveabrock.com">deploys Blazor WebAssembly to Azure Static Web Apps</a>.</li><li>Silambarasan Ilango <a href="https://www.syncfusion.com/blogs/post/how-to-authenticate-a-blazor-webassembly-hosted-app-with-azure-active-directory.aspx?ref=daveabrock.com">authenticates a Blazor WASM app with Azure AD</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/01/18/using-asp-net-core-controllers-and-razor-pages-from-a-separate-shared-project-or-assembly/?ref=daveabrock.com">uses ASP.NET Core Controllers and Razor Pages from a separate shared project or assembly</a>.</li><li>David Grace <a href="https://www.telerik.com/blogs/how-blazor-performs-against-other-frameworks?ref=daveabrock.com">explores how Blazor performs against other frameworks</a>.</li><li>Shawn Wildermuth <a href="http://wildermuth.com/2021/01/17/Forcing-ASP-NET-WebForms-Designer-Files-to-Regenerate?ref=daveabrock.com">forces ASP.NET WebForms Designer files to regenerate</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/how-to-fix-blazor-wasm-base-path-problems/?ref=daveabrock.com">fixes Blazor WASM base path problems</a>.</li><li>Over at Code Maze, <a href="https://code-maze.com/download-files-dot-net-core-angular/?ref=daveabrock.com">they write about downloading files with ASP.NET Core Web API and Angular</a>.</li><li>Joseph Guadagno <a href="https://www.josephguadagno.net/2021/01/18/using-yarn-with-asp-net-core-projects?ref=daveabrock.com">uses Yarn with ASP.NET Core projects</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Bryan Soltis <a href="https://soltisweb.com/blog/detail/2020-05-20-connectinganazurelogicapptoalocalwebapi?ref=daveabrock.com">connects an Azure Logic Web App to a local Web API</a>.</li><li>Jonathan George <a href="https://endjin.com/blog/2021/01/how-to-trigger-an-azure-synapse-pipeline-run-from-csharp.html?ref=daveabrock.com">triggers an Azure Synapse pipeline run from C#</a>.</li><li>Mark Heath <a href="https://markheath.net/post/azure-cli-access-restrictions?ref=daveabrock.com">automates Azure access restrictions with the Azure CLI</a>.</li><li>Justin Yoo <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/cloudevents-for-azure-eventgrid-via-azure-functions?ref=daveabrock.com">uses Azure Functions to work with CloudEvents for Azure EventGrid</a>.</li><li>Bryan Soltis <a href="https://soltisweb.com/blog/detail/2020-08-19-importingopenapiapiintoazureapim?ref=daveabrock.com">imports an OpenAPI API into Azure API Management</a>.</li><li>Johan Danforth <a href="https://weblogs.asp.net/jdanforth/how-to-setup-continuous-integration-and-deploy-pipeline-for-asp-net-mvc-framework-application-to-azure-web-app?ref=daveabrock.com">sets up CI/CD to push an ASP.NET MVC app to Azure Web App</a>.</li><li>Brendan Burns <a href="https://twitter.com/dustinmoris/status/1351842103475765248?ref=daveabrock.com">chimes in on a concern about AKS utilization</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/flatten-strings-with-regex-replace?ref=daveabrock.com">flattens strings with RegEx.Replace</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/01/19/config-top-level-programs?ref=daveabrock.com">uses configuration with C# 9 top-level programs</a>.</li><li>Mark Downie <a href="https://www.poppastring.com/blog/view-the-origin-of-a-repeating-call-stack?ref=daveabrock.com">writes about viewing the origin of a repeating call stack</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/01/21/bulk-copy-with-entity-framework-core-5/?ref=daveabrock.com">performs a bulk copy with EF Core 5</a>.</li><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-01-22-extending-the-github-cli/?ref=daveabrock.com">extends the GitHub CLI</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/19/ef-core-plans.aspx?ref=daveabrock.com">writes about what developers want with EF 6</a>, and also <a href="https://visualstudiomagazine.com/articles/2021/01/19/net-porting-tool.aspx?ref=daveabrock.com">writes about AWS open sourcing the .NET porting assistant GUI</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/new-features-for-unit-testing-your-entity-framework-core-5-code/?ref=daveabrock.com">writes about new features for unit testing EF Core 5</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Jan/14/Taking-the-new-Chromium-WebView2-Control-for-a-Spin-in-NET-Part-1?ref=daveabrock.com">takes the new Chromium WebView2 control for a spin in .NET</a>.</li><li>Julie Lerman <a href="http://thedatafarm.com/data-access/entity-framework-core-5-resources/?ref=daveabrock.com">keeps us updated on what she’s working on</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/visual-studio-intellicode-ai-assisted-coding/?ref=daveabrock.com">writes about Visual Studio IntelliCode</a>.</li><li>Miguel Bernard <a href="https://blog.miguelbernard.com/figuring-out-stages-in-yaml-pipelines?ref=daveabrock.com">figures out stages in YAML pipelines</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Rendy Del Rosario <a href="https://www.xamboy.com/2021/01/20/using-dynamic-data-in-xamarin-forms-part-1/?ref=daveabrock.com">uses dynamic data in Xamarin Forms</a>.</li><li>CodeChem <a href="https://hackernoon.com/how-to-set-up-a-xamarin-forms-app-with-sqlite-local-storage-dw3z31q0?source=rss">sets up a Xamarin app with SQLite local storage</a>.</li></ul><h2 id="-design-testing-and-best-practices">🏗 Design, testing, and best practices</h2><ul><li>Jeremy Miller <a href="https://jeremydmiller.com/2021/01/21/re-evaluating-the-double-ds-of-software-development-test-driven-development/?ref=daveabrock.com">re-evaluates test-driven development</a>.</li><li>Stephen Cleary <a href="https://blog.stephencleary.com/2021/01/asynchronous-messaging-3-backend-processor.html?ref=daveabrock.com">continues his series on asynchronous messaging</a>.</li><li>Steve Smith <a href="https://ardalis.com/mvc-controllers-are-dinosaurs-embrace-api-endpoints/?ref=daveabrock.com">writes about embracing API endpoints over controllers</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Azure Podcast <a href="http://azpodcast.azurewebsites.net/post/Episode-361-Project-Natick?ref=daveabrock.com">talks to the Project Natick team</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1723&ref=daveabrock.com">talks to Tom Kerkhove about containers on Azure</a>.</li><li>The Coding After Work podcast <a href="http://codingafterwork.com/2021/01/15/episode-54-uno-platform-why-aot-is-awesome-and-toast-with-jerome-laban/?ref=daveabrock.com">talks with Jérôme Laban about Uno and AOT</a>.</li><li>The Coding Blocks podcast asks: <a href="https://www.codingblocks.net/podcast/who-owns-open-source-software/?ref=daveabrock.com">who owns open-source software</a>?</li><li>The Adventures in .NET podcast <a href="https://devchat.tv/adventures-in-dotnet/net-052-abusing-c-calendars-epochs-and-the-net-functions-framework-with-jon-skeet/?ref=daveabrock.com">talks to Jon Skeet</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-179-uno-platform-with-jerome-laban/?ref=daveabrock.com">talks about Uno with Jérôme Laban</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>James Montemagno <a href="https://www.youtube.com/watch?v=y8ZqEOLDeo8&ref=daveabrock.com">works with MVVM Helpers</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Azure-SQL-Connectivity-Performance-Tips--Tricks?ref=daveabrock.com">talks about Azure SQL connectivity performance tips and tricks</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2021/01/18/KevinGriffinOnSignalRRealWorldProjects.aspx?ref=daveabrock.com">David Giard talks to Kevin Griffin about SignalR</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=NGgHJ8HJ1-s&ref=daveabrock.com">talk to Adam Dymitruk about event modeling</a>, and also <a href="https://www.youtube.com/watch?v=2TeKeGOQGeg&ref=daveabrock.com">talk with Scott Hunter</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Signed HTTP Exchanges: A path for Blazor WebAssembly instant runtime loading? ]]></title>
        <description><![CDATA[ We explore Signed HTTP Exchanges, which may help when loading the .NET runtime in Blazor WebAssembly apps. ]]></description>
        <link>https://www.daveabrock.com/2021/01/26/signed-http-exchanges-cdn-cache/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe87</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 25 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1607434472257-d9f8e57a643d?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDI3fHxsb2FkaW5nfGVufDB8fHx8MTYxOTgzMjk5MQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Before you sit down and write the next great Blazor application, you first need to think about <a href="https://docs.microsoft.com/aspnet/core/blazor/hosting-models?view=aspnetcore-5.0&ref=daveabrock.com">hosting</a>: Blazor Server or Blazor WebAssembly? I’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com#hosting-models">written about this quite a bit</a>, but I’ll provide a condensed version for you.</p><p>Blazor Server executes your app on the server from an ASP.NET Core app. JS calls, event handling, and UI updates are managed over a persistent SignalR connection. In this case, the app loads much faster, you can enjoy .NET Core APIs on the server, and your apps work with browsers that don’t support WebAssembly.</p><p>For Blazor WebAssembly, there’s no server-side dependency, you can leverage client capabilities, and it works great for serverless deployment scenarios. For example, <a href="https://daveabrock.com/tags?ref=daveabrock.com#blast-off-blazor">in my <em>Blast Off with Blazor series</em></a>, it’s served using Blazor WebAssembly and Azure Functions—I only have to pay for compute.</p><p>The biggest drawback to Blazor WebAssembly, of course, is the runtime download size. With no runtime dependency, users need to wait for the .NET runtime to load in the browser. While it’s getting smaller thanks to IL trimming and other techniques, it still is a major factor to consider. You can definitely help with initial load time—thanks to <a href="https://daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm?ref=daveabrock.com">server prerendering</a> and <a href="https://www.meziantou.net/optimizing-a-blazor-webassembly-application-size.htm?ref=daveabrock.com">other techniques</a>—but the download size will always be a factor. Or will it?</p><p>In a recent interview <a href="https://daveabrock.com/2021/01/17/dev-discussions-steve-sanderson?ref=daveabrock.com">with Blazor creator Steve Sanderson</a>, I posed this question: do we see a point where it’ll ever be as lightweight as leading front-end frameworks, or will we need to understand it’s a cost that comes with a full framework in the browser?</p><p>Here’s what he said:</p><blockquote>The size of the .NET runtime isn’t ever going to reduce to near-zero, so JS-based microframeworks (whose size could be just a few KB) are always going to be smaller. We’re not trying to win outright based on size alone—that would be madness. Blazor WebAssembly is aimed to be maximally productive for developers while being small enough to download that, in very realistic business app scenarios, the download size shouldn’t be any reason for concern.</blockquote><blockquote>That said, it’s conceivable that new web platform features like Signed HTTP Exchanges could let us smartly pre-load the .NET WebAssembly runtime in a browser in the background (directly from some Microsoft CDN) while you’re visiting a Blazor WebAssembly site, so that it’s instantly available at zero download size when you go to other Blazor WebAssembly sites. <a href="https://developers.google.com/web/updates/2018/11/signed-exchanges?ref=daveabrock.com">Signed HTTP Exchanges</a> allow for a modern equivalent to the older idea of a cross-site CDN cache. We don’t have a definite plan about that yet as not all browsers have added support for it.</blockquote><p>Interesting! I’ve read about Signed HTTP Exchanges before but not in the context of a cross-site CDN cache. In this post, I’d like to unpack the concept of a cross-site CDN cache, describe Signed HTTP Exchanges, and how this new technology <em>might</em> possibly help with downloading the .NET runtime in the browser for Blazor WebAssembly apps.</p><p>To be clear, I’m not saying that Microsoft plans on using Signed HTTP Exchanges to assist with Blazor WebAssembly browser load time. I’m exploring the technology here to understand how it all works.</p><h2 id="the-value-of-a-cross-site-cdn-cache-">The value of a “cross-site CDN cache”</h2><p>Before we discuss the values of a cross-site CDN cache, let’s briefly discuss a few big reasons why you might want to use a Content Delivery Network (CDN) to store your resources instead of handling it yourself:</p><ul><li><strong>Better content availability</strong> - because CDNs are typically distributed worldwide, they can handle more traffic easily. You can trust that something hosted by a Google or a Microsoft will withstand the pressures of the modern web.</li><li><strong>Faster load times</strong> -  because CDNs are typically globally distributed, you can serve content to users closer to their location</li><li><strong>Cost reduction</strong> - through <em>caching</em> and other optimization techniques, CDNs can reduce the data footprint</li></ul><p>It’s the <em>caching</em> we want to focus on here. How does this relate to cross-site caching? This is definitely not a new idea. Let’s think about the <a href="https://jquery.com/?ref=daveabrock.com">jQuery library</a>. (While it isn’t as popular as it once was, it’s still <a href="https://trends.builtwith.com/javascript/jQuery?ref=daveabrock.com">all over the web</a>, including in your latest ASP.NET Core project templates.)</p><p>The idea of cross-site CDN caching is simple. If folks all over the world are accessing a ubiquitous library like jQuery from its official CDN, the odds are high that they already have a cached script file in their browser from a visit to another website. This significantly speeds up script load time when users make their way to your site.</p><p>Will Blazor ever be as ubiquitous across the web as jQuery once was? Time will tell. But it’s a reasonable strategy to address how to load the .NET runtime in the browser. It isn’t as simple as asking Microsoft to stand up a new CDN, as this pattern <a href="https://www.stefanjudis.com/notes/say-goodbye-to-resource-caching-across-sites-and-domains/?ref=daveabrock.com">invites tracking abuse</a> and potential security problems. We need a modern approach. Let’s see if Signed HTTP Exchanges can help.</p><h2 id="enter-signed-http-exchanges">Enter Signed HTTP Exchanges</h2><p>Here’s an elevator pitch for Signed HTTP Exchanges, <a href="https://developers.google.com/web/updates/2018/11/signed-exchanges?ref=daveabrock.com">taken straight from Google</a>:</p><blockquote>Signed HTTP Exchange (or “SXG”) … enables publishers to safely make their content portable, i.e. available for redistribution by other parties, while still keeping the content’s integrity and attribution. Portable content has many benefits, from enabling faster content delivery to facilitating content sharing between users, and simpler offline experiences.</blockquote><p>This especially helps with serving content from third-party caches. If Microsoft has a CDN to host the Blazor WebAssembly runtime bits, they could leverage SXG to make this possible.</p><p>How does this work? When a publisher <a href="https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html?ref=daveabrock.com#rfc.section.3">signs an HTTP exchange</a> (a request/response pair) from any cached server, the content can be published and referenced elsewhere on the web without a dependency on a server, connection, or even a hosting service. Feel free to <a href="https://web.dev/signed-exchanges/?ref=daveabrock.com">geek out on the juicy details</a>. (If you’re a publisher, you enable this by generating a certificate key to generate a signature with a special <a href="https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html?ref=daveabrock.com#cross-origin-cert-req">CanSignHttpExchanges extension</a>.)</p><p>As the main use case is delivering a page’s main document, sites could leverage it by using an <code>a</code> or <code>link</code> tag:</p><pre><code>&lt;a href="https://myexample.com/sxg"&gt;
</code></pre><pre><code class="language-html">&lt;link rel="prefetch" as="document" href="https://myexample.com/sxg"&gt;
</code></pre><p>In our case, Microsoft could use SXG preloading to download the runtime in the background, cache it, then allowing for a lightning-quick experience as you navigate other Blazor WebAssembly sites. As we think about how we load resources today, it’s done over a <code>&lt;script&gt;</code> tag. This approach in SXG—called subresource loading—is <a href="https://web.dev/signed-exchanges/?ref=daveabrock.com#loading-sxgs">currently not recommended</a>, but it may change over time.</p><h2 id="browser-support">Browser support</h2><p>Over at <em>caniuse.com</em>, you can see <a href="https://caniuse.com/sxg?ref=daveabrock.com">how browser support looks</a>—at the time of this writing it enjoys around 67% support for users worldwide. Edge, Chrome, and Opera rolled out support for it around the spring of 2020, and Firefox does not support it yet.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/can-i-sxg.png" class="kg-image" alt="Browser support for SXG" loading="lazy" width="2000" height="935" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/can-i-sxg.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/can-i-sxg.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/can-i-sxg.png 1600w, https://www.daveabrock.com/content/images/2021/05/can-i-sxg.png 2042w" sizes="(min-width: 720px) 720px"></figure><p>In addition to this, SXGs support advanced content negotiation. This means you can serve both SXG and non-SXG versions of the same content, <a href="https://web.dev/signed-exchanges/?ref=daveabrock.com#content-negotiation">depending on if a browser supports it</a>.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we talked about Signed HTTP Exchanges and how it might help with loading the .NET runtime in the browser. It’s always scary writing about a new topic that’s subject to change—so please let me know if you have any suggestions or corrections.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #33: 🚀 A blazing conversation with Steve Sanderson ]]></title>
        <description><![CDATA[ It&#39;s a jam-packed issue this week, as we talk about Blazor with Steve Sanderson. ]]></description>
        <link>https://www.daveabrock.com/2021/01/23/dotnet-stacks-33/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe86</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 22 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-12.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Happy Monday, all. What did you get NuGet <a href="https://devblogs.microsoft.com/nuget/happy-10th-birthday-nuget/?ref=daveabrock.com">for its 10th birthday</a>?</p><p>This week:</p><ul><li>Microsoft blogs about more .NET 5 improvements</li><li>A study on migrating a hectic service to .NET Core</li><li>Meet Jab, a new compile-time DI library</li><li>Dev Discussions: Steve Sanderson</li><li>Last week in the .NET world</li></ul><hr><h2 id="microsoft-blogs-about-more-net-5-improvements">Microsoft blogs about more .NET 5 improvements</h2><p>This week, Microsoft pushed a few more blog posts to promote .NET 5 improvements: Sourabh Shirhatti <a href="https://devblogs.microsoft.com/dotnet/diagnostics-improvements-in-net-5/?ref=daveabrock.com">wrote about diagnostic improvements</a>, and Máňa Píchová <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/?ref=daveabrock.com">writes about .NET networking improvements</a>.</p><h3 id="diagnostic-improvements">Diagnostic improvements</h3><p>With .NET 5, the diagnostic suite of tools does not require installing them as .NET global tools—they can now be installed without the .NET SDK. There’s now a single-file distribution mechanism that only requires a runtime of .NET Core 3.1 or higher. You can <a href="https://github.com/dotnet/diagnostics/blob/master/documentation/single-file-tools.md?ref=daveabrock.com">check out the GitHub repo</a> to geek out on all the available diagnostics tools. In other news, you can now perform startup tracing from EventPipe as the tooling can now suspend the runtime during startup until a tool is connected. Check out the <a href="https://devblogs.microsoft.com/dotnet/diagnostics-improvements-in-net-5/?ref=daveabrock.com">blog post for the full treatment</a>.</p><h3 id="networking-improvements">Networking improvements</h3><p>In terms of .NET 5 networking improvements, the team added the ability to use cancellation timeouts from <code>HttpClient</code> without the need for a custom <code>CancellationToken</code>. While the client still throws a <code>TaskCanceledException</code>, the inner exception is a <code>TimeoutException</code> when timeouts occur. .NET 5 also supports <a href="https://github.com/dotnet/diagnostics/blob/master/documentation/single-file-tools.md?ref=daveabrock.com">multiple connections with HTTP/2</a>, a <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/?ref=daveabrock.com#configurable-ping">configurable ping mechanism</a>, <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/?ref=daveabrock.com#http-3">experimental support for HTTP/3</a>, and <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/?ref=daveabrock.com#telemetry">various telemetry improvements</a>. Check out the <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements?ref=daveabrock.com">networking blog post for details</a>. It’s a nice complement to <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/?ref=daveabrock.com">Stephen Toub’s opus about .NET 5 performance improvements</a>.</p><hr><h2 id="a-study-on-migrating-a-hectic-service-to-net-core">A study on migrating a hectic service to .NET Core</h2><p>This week, Avanindra Paruchuri <a href="https://devblogs.microsoft.com/dotnet/azure-active-directorys-gateway-service-is-on-net-core-3-1/?ref=daveabrock.com">wrote about migrating the Azure Active Directory gateway</a>—and its 115 billion daily requests—over to .NET Core. While there’s nothing preventing you hosting .NET Framework apps in the cloud, the bloat of the framework often leads to expensive cloud spend.</p><blockquote>The gateway’s scale of execution results in significant consumption of compute resources, which in turn costs money. Finding ways to reduce the cost of executing the service has been a key goal for the team behind it. The buzz around .NET Core’s focus on performance caught our attention, especially since TechEmpower listed ASP.NET Core as one of the fastest web frameworks on the planet.</blockquote><blockquote>In Azure AD gateway’s case, we were able to cut our CPU costs by 50%. As a result of the gains in throughput, we were able to reduce our fleet size from ~40k cores to ~20k cores (50% reduction) … Our CPU usage was reduced by half on .NET Core 3.1 compared to .NET Framework 4.6.2 (effectively doubling our throughput).</blockquote><p>It’s a nice piece on how they were able to gradually move over and gotchas they learned along the way.</p><hr><h2 id="meet-jab-a-new-compile-time-di-library">Meet Jab, a new compile-time DI library</h2><p>This week, Pavel Krymets introduced Jab, a <a href="https://github.com/pakrym/jab?ref=daveabrock.com">library used for compile-time dependency injection</a>. Pavel works with the Azure SDKs and used to work on the ASP.NET Core team. Remember a few weeks ago, when we said that innovation in C# source generators will be coming in 2021? Here we go.</p><p>From the GitHub readme, it promises fast startup (200x more than <code>Microsoft.Extensions.DependencyInjection</code>), fast resolution (a 7x improvement), no runtime dependencies, with all code generating during project compilation. Will it run on ASP.NET Core? Not likely, since ASP.NET Core is heavily dependent on the runtime thanks to type accessibility and dependency discovery, but Pavel <a href="https://twitter.com/pakrym/status/1348862830368358401?ref=daveabrock.com">wonders if there’s a middle ground</a>.</p><hr><h2 id="dev-discussions-steve-sanderson">Dev Discussions: Steve Sanderson</h2><p>It seems like forever ago when, <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">at NDC Oslo in 2017</a>, Steve Sanderson showed off a new web UI framework with the caveat: “<em>an experiment, something for you to be amused by</em>.” By extending <a href="https://github.com/chrisdunelm/DotNetAnywhere?ref=daveabrock.com">Dot Net Anywhere</a> (DNA), Chris Bacon’s portable .NET runtime, on WebAssembly, he was able to load and run C# in the browser. In the browser!</p><p>Of course, this amusing experiment has grown <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor?ref=daveabrock.com">into Blazor</a>, a robust system for writing web UIs in C#. I was happy to talk to Steve Sanderson about his passions for the front-end web, how far Blazor has come, and what’s coming to Blazor in .NET 6.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/steve-sanderson-1.jpg" class="kg-image" alt="Steve Sanderson profile photo" loading="lazy" width="350" height="350"></figure><h3 id="years-ago-you-probably-envisioned-what-blazor-could-be-has-it-met-its-potential-or-are-there-other-areas-to-focus-on">Years ago, you probably envisioned what Blazor could be. Has it met its potential, or are there other areas to focus on?</h3><p>We’re not there yet. If you go on YouTube and find the <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">first demo I ever did of Blazor at NDC Oslo in 2017</a>, you’ll see my original prototype had near-instant live reloading while coding, and the download size was really tiny. I still aspire to get the real version of Blazor to have those characteristics. Of course, the prototype had the advantage of only needing to do a tiny number of things—creating a production-capable version is 100x more work, which is why it hasn’t yet got there, but has of course exceeded the prototype vastly in more important ways.</p><p>Good news though is that in .NET 6 <a href="https://github.com/dotnet/aspnetcore/issues/5456?ref=daveabrock.com">we expect to ship</a> an even better version of live-updating-while-coding than I had in that first prototype, so it’s getting there!</p><h3 id="when-looking-at-aot-you-ll-see-increased-performance-but-a-larger-download-size-do-you-see-any-other-tradeoffs-developers-will-need-to-consider">When looking at AOT, you’ll see increased performance but a larger download size. Do you see any other tradeoffs developers will need to consider?</h3><p>The mixed-mode flavour of AOT, in which some of your code is interpreted and some is AOT, allows for a customizable tradeoff between size and speed, but also includes some subtleties like extra overhead when calling from AOT to interpreted code and vice-versa.</p><p>Also, when you enable AOT, your app’s publish time may go up substantially (maybe by 5-10 minutes, depending on code size) because the whole <a href="https://emscripten.org/?ref=daveabrock.com">Emscripten toolchain</a> just takes that long. This wouldn’t affect your daily development flow on your own machine, but likely means your CI builds could take longer.</p><h3 id="it-s-still-quite-impressive-to-see-the-entire-net-runtime-run-in-the-browser-for-blazor-web-assembly-that-comes-with-an-upfront-cost-as-we-know-i-know-that-the-blazor-team-has-done-a-ton-of-work-to-help-lighten-the-footprint-and-speed-up-performance-with-the-exception-of-aot-do-you-envision-more-work-on-this-do-you-see-a-point-where-it-ll-be-as-lightweight-as-other-leading-front-end-frameworks-or-will-folks-need-to-understand-it-s-a-cost-that-comes-with-a-full-framework-in-the-browser">It’s still quite impressive to see the entire .NET runtime run in the browser for Blazor Web Assembly. That comes with an upfront cost, as we know. I know that the Blazor team has done a ton of work to help lighten the footprint and speed up performance. With the exception of AOT, do you envision more work on this? Do you see a point where it’ll be as lightweight as other leading front-end frameworks, or will folks need to understand it’s a cost that comes with a full framework in the browser?</h3><p>The size of the .NET runtime isn’t ever going to reduce to near-zero, so JS-based microframeworks (whose size could be just a few KB) are always going to be smaller. We’re not trying to win outright based on size alone—that would be madness. Blazor WebAssembly is aimed to be maximally productive for developers while being small enough to download that, in very realistic business app scenarios, the download size shouldn’t be any reason for concern.</p><p>That said, it’s conceivable that new web platform features like <a href="https://developers.google.com/web/updates/2018/11/signed-exchanges?ref=daveabrock.com">Signed HTTP Exchanges</a> could let us smartly pre-load the .NET WebAssembly runtime in a browser in the background (directly from some Microsoft CDN) while you’re visiting a Blazor WebAssembly site, so that it’s instantly available at zero download size when you go to other Blazor WebAssembly sites. Signed HTTP Exchanges allow for a modern equivalent to the older idea of a cross-site CDN cache. We don’t have a definite plan about that yet as not all browsers have added support for it.</p><p><em>Check out the <a href="https://daveabrock.com/2021/01/17/dev-discussions-steve-sanderson?ref=daveabrock.com">entire interview at my site</a>.</em></p><hr><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/an-introduction-to-the-data-protection-system-in-asp-net-core/?ref=daveabrock.com">introduces the ASP.NET Core Data Protection system</a>.</li><li>Maarten Balliauw <a href="https://blog.maartenballiauw.be/post/2021/01/13/the-process-thought-and-technology-behind-building-a-friendly-net-sdk-for-jetbrains-space.html?ref=daveabrock.com">writes about building a friendly .NET SDK</a>.</li><li>Josef Ottosson <a href="https://josef.codes/azure-storage-zip-multiple-files-using-azure-functions/?ref=daveabrock.com">writes an Azure Function to zip multiple files from Azure Storage</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>Shelley Bransten <a href="https://cloudblogs.microsoft.com/industry-blog/retail/2021/01/13/introducing-microsoft-cloud-for-retail/?ref=daveabrock.com">announces Microsoft Cloud for Retail</a>.</li><li>Christopher Gill <a href="https://devblogs.microsoft.com/nuget/happy-10th-birthday-nuget?ref=daveabrock.com">celebrates NuGet’s 10th birthday</a>.</li><li>Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-january-security-and-quality-rollup-update?ref=daveabrock.com">releases the January 2021 Security and Quality Rollup Updates for .NET Framework</a>, and Rahul Bhandari <a href="https://devblogs.microsoft.com/dotnet/net-january-2021?ref=daveabrock.com">writes about the .NET January 2021 updates</a>.</li><li>.NET 6 nightly builds for Apple M1 <a href="https://t.co/3SZmy73Z10?amp=1&ref=daveabrock.com">are now available</a>.</li><li>The Visual Studio team <a href="https://t.co/NMJgBobHzR?amp=1&ref=daveabrock.com">wants your feedback</a> on Razor syntax coloring.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=biL1XOcg8Us&ref=daveabrock.com">talks to Luis Quintanilla about F#</a>.</li><li>Pavel Krymets <a href="https://t.co/NnOE2bnefq?amp=1&ref=daveabrock.com">introduces Jab</a>, a compile-time DI container.</li><li>The Entity Framework Standup <a href="https://www.youtube.com/watch?v=IiAS61uVDqE&ref=daveabrock.com">talks about EF Core 6 survey results</a>, and the Languages &amp; Runtime standup <a href="https://www.youtube.com/watch?v=jv84Ewh28OI&ref=daveabrock.com">discusses plans for .NET 6 and VB source generators</a>.</li><li>Sarah Novotny <a href="https://cloudblogs.microsoft.com/opensource/2021/01/14/four-open-source-lessons?ref=daveabrock.com">writes about 4 open source lessons for 2021</a>.</li><li>IdentityServer v5 <a href="https://blog.duendesoftware.com/posts/20210114_v5_release/?ref=daveabrock.com">has shipped</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/rethinking-oss-attribution-in-net?ref=daveabrock.com">rethinks OSS attribution in .NET</a>.</li><li>TechBash 2021 <a href="https://www.techbash.com/blog/2021/01/14/announcing-techbash-2021?ref=daveabrock.com">is slated for October 19-22, 2021</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Dave Brock <a href="https://daveabrock.com/2021/01/14/blast-off-blazor-search-box?ref=daveabrock.com">builds a “search-as-you-type” box in Blazor</a>.</li><li>Cody Merritt Anhorn <a href="https://codyanhorn.tech/blog/2021/01/13/Blazor-Getting-Started-with-Localization.html?ref=daveabrock.com">uses localization with Blazor</a>.</li><li>Changhui Xu <a href="https://codeburst.io/upload-files-with-angular-and-net-web-api-77a7966ed226?ref=daveabrock.com">uploads files with Angular and .NET Web API</a>.</li><li>Mark Pahulje <a href="http://metadataconsulting.blogspot.com/2021/01/CSharp-dotNet-How-to-get-all-emails-from-a-HTML-page-with-a-href-inner-text.html?ref=daveabrock.com">uses HtmlAgilityPack to get all emails from an HTML page</a>.</li><li>Jon Hilton <a href="https://jonhilton.net/blazor-tailwind-dark-mode-local-storage/?ref=daveabrock.com">uses local storage with Blazor</a>.</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2021/01/13/grpc-asp-net-core-5-test-grpc-endpoints-with-grpcurl/?ref=daveabrock.com">tests gRPC endpoints with gRPCurl</a>, and <a href="https://anthonygiretti.com/2021/01/17/grpc-asp-net-core-5-discover-grpcui-the-gui-alternative-to-grpcurl/?ref=daveabrock.com">also explores gRPCui</a>.</li><li>The folks at Uno <a href="https://platform.uno/blog/how-to-build-a-single-page-web-app-in-xaml-and-c-with-webassembly-using-uno-platform/?ref=daveabrock.com">write about building a single-page app in XAML and C# with WebAssembly</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/query-strings-blazor-webassembly/?ref=daveabrock.com">handles query strings in Blazor WebAssembly</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-ASP-NET-Core-API-Integration-With-Azure-Cosmos-DB/?ref=daveabrock.com">continues building out his ASP.NET Core Web API by integrating with Azure Cosmos DB</a>.</li></ul><h3 id="-the-net-platform">🥅 The .NET platform</h3><ul><li>Sean Killeen <a href="https://flavorsof.net/?ref=daveabrock.com">describes the many flavors of .NET</a>.</li><li>Mattias Karlsson <a href="https://www.devlead.se/posts/2021/2021-01-15-my-preferred-console-stack?ref=daveabrock.com">writes about his boilerplate starting point for .NET console apps</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/15/net-5-improvements.aspx?ref=daveabrock.com">delivers a one-stop shop for .NET 5 improvements</a>.</li><li>Sam Walpole <a href="https://dev.to/dr_sam_walpole/writing-decoupled-code-with-mediatr-the-mediator-pattern-34p5?ref=daveabrock.com">discusses writing decoupled code with MediatR</a>.</li><li>Sourabh Shirhatti <a href="https://devblogs.microsoft.com/dotnet/diagnostics-improvements-in-net-5?ref=daveabrock.com">writes about diagnostics improvements with .NET 5</a>.</li><li>Máňa Píchová <a href="https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements?ref=daveabrock.com">writes about .NET 5 networking improvements</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Avanindra Paruchuri <a href="https://devblogs.microsoft.com/dotnet/azure-active-directorys-gateway-service-is-on-net-core-3-1?ref=daveabrock.com">writes about migrating the Azure AD gateway to .NET Core</a>.</li><li>Johnny Reilly <a href="https://blog.johnnyreilly.com/2021/01/azure-easy-auth-and-roles-with-dotnet-and-core.html?ref=daveabrock.com">works with Azure Easy Auth</a>.</li><li>Muhammed Saleem <a href="https://code-maze.com/creating-serverless-apps-with-dotnet-using-azure-functions/?ref=daveabrock.com">works with Azure Functions</a>.</li><li>Chris Noring <a href="https://dev.to/azure/using-azure-key-vault-to-manage-your-secrets-546g?ref=daveabrock.com">uses Azure Key Vault to manage secrets</a>.</li><li>Bryan Soltis <a href="https://soltisweb.com/blog/detail/2020-11-10-howtopostafiletoazurefunctionin3minutes?ref=daveabrock.com">posts a file to an Azure Function in 3 minutes</a>.</li><li>Damian Brady <a href="https://devblogs.microsoft.com/devops/generate-a-github-actions-workflow-with-visual-studio-or-the-dotnet-cli?ref=daveabrock.com">generates a GitHub Actions workflow with Visual Studio or the dotnet CLI</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/building-and-testing-on-multiple-net-versions-with-github-actions/?ref=daveabrock.com">builds and tests multiple .NET versions with GitHub Actions</a>.</li><li>Dominique St-Amand <a href="https://www.domstamand.com/integration-tests-using-azure-storage-emulator-and-net-core-in-azure-devops/?ref=daveabrock.com">works with integration tests using Azure Storage emulator and .NET Core in Azure DevOps</a>.</li><li>Aaron Powell <a href="https://www.aaron-powell.com/posts/2021-01-11-using-environments-for-approval-workflows-with-github/?ref=daveabrock.com">uses environments for approval workflows with GitHub Actions</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/01/11/protecting-legacy-apis-with-an-asp-net-core-yarp-reverse-proxy-and-azure-ad-oauth/?ref=daveabrock.com">protects legacy APIs with an ASP.NET Core YARP reverse proxy and Azure AD Auth</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/base64-encoding-with-csharp?ref=daveabrock.com">writes about Base64 encoding with C#</a>.</li><li>Franco Tiveron <a href="https://developer.okta.com/blog/2021/01/13/developers-cheatsheet-csharp-9?ref=daveabrock.com">writes about a developer’s C# 9 cheat sheet</a>.</li><li>Bruno Sonnino <a href="https://blogs.msmvps.com/bsonnino/2021/01/08/converting-xml-data-to-json/?ref=daveabrock.com">uses C# to convert XML data to JSON</a>.</li><li>Jacob E. Shore <a href="https://dev.to/dewofyouryouth_43/first-impressions-of-f-1g9m?ref=daveabrock.com">writes about his first impressions of F#</a>.</li><li>Matthew Crews <a href="https://matthewcrews.com/blog/2021/01/2021-01-09/?ref=daveabrock.com">writes about learning resources for F#</a>.</li><li>Mark-James McDougall <a href="https://markjames.dev/2021-01-08-writing-an-iracing-sdk-implementation-fsharp/?ref=daveabrock.com">writes an iRacing SDK implementation in F#</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Elton Stoneman <a href="https://blog.sixeyed.com/understanding-microsofts-docker-images-for-net-apps/?ref=daveabrock.com">writes about understanding Microsoft’s Docker images for .NET apps</a>.</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/updating-many-to-many-relationships-in-ef-core-5-and-above/?ref=daveabrock.com">writes about updating many-to-many relationships in EF Core 5 and above</a>.</li><li>Ruben Rios <a href="https://devblogs.microsoft.com/visualstudio/a-more-integrated-terminal-experience?ref=daveabrock.com">writes about a more integrated terminal experience with Visual Studio</a>.</li><li>Benjamin Day <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-for-mac-helps-you-write-tests?ref=daveabrock.com">writes about tests in Visual Studio for Mac</a>.</li><li>The folks at Packt <a href="https://hackernoon.com/microsofts-dapr-distributed-application-runtime-an-overview-nd2m34gj?source=rss">write about DAPR</a>.</li><li>Peter De Tender <a href="https://devblogs.microsoft.com/devops/publishing-azure-container-instances-from-docker-cli?ref=daveabrock.com">publishes Azure Container Instances from the Docker CLI</a>.</li><li>Nikola Zivkovic <a href="https://rubikscode.net/2021/01/11/machine-learning-with-ml-net-linear-regression/?ref=daveabrock.com">writes about linear regression with ML.NET</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/how-we-quickly-refactored-with-resharper-more-than-23-000-calls-to-debug-assert-into-more-meaningful-assertions/?ref=daveabrock.com">writes how NDepend used Resharper to quickly refactored more than 23,000 calls to Debug.Assert()</a>.</li><li>Mark Heath <a href="https://markheath.net/post/naudio-2-plans?ref=daveabrock.com">discusses his plans for NAudio 2</a>.</li><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/01/10/entity-framework-core-is-it-fast?ref=daveabrock.com">asks: is Entity Framework Core fast</a>?</li><li>Jon P. Smith <a href="https://www.thereformedprogrammer.net/introducing-the-efcore-softdeleteservices-library-to-automate-soft-deletes/?ref=daveabrock.com">introduces a library to automate soft deletes in EF Core</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/design-for-developers-introduction-xamarin-forms?ref=daveabrock.com">introduces UX design with Xamarin Forms</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/xaml-naming-conventions-in-xamarin-forms/?ref=daveabrock.com">writes about XAML naming conventions in Xamarin.Forms</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/infogram-about-xamarin-forms-5-0-%f0%9f%98%8d/?ref=daveabrock.com">works with the Infogram in Xamarin.Forms 5.0</a>.</li><li>Rafael Veronezi <a href="https://www.mfractor.com/blogs/news/previewing-xaml-uis-in-xamarin-forms?ref=daveabrock.com">previews XAML UIs</a>.</li><li>James Montemagno <a href="https://montemagno.com/how-to-add-support-email-xamarin-apps/?ref=daveabrock.com">writes about how to integrate support emails in mobile apps with data and logs</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/knowing-the-file-picker-in-xamarin-forms/?ref=daveabrock.com">writes about the Xamarin.Forms File Picker</a>.</li></ul><h3 id="-design-testing-and-best-practices">👍 Design, testing, and best practices</h3><ul><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/how-to-become-a-better-developer-by-asking-questions?ref=daveabrock.com">writes about how to become a better developer by asking questions</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/start-with-a-monolith-not-microservices/?ref=daveabrock.com">says: start with a monolith, not microservices</a>.</li><li>Stephen Cleary <a href="https://blog.stephencleary.com/2021/01/asynchronous-messaging-2-durable-queues.html?ref=daveabrock.com">writes about durable queues</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>Scott Hanselman <a href="https://hanselminutes.simplecast.com/episodes/exploring-event-modeling-with-adam-dymitruk-xvAdQlCd?ref=daveabrock.com">explores event modeling with Adam Dymitruk</a>.</li><li>At Working Code podcast, <a href="https://www.bennadel.com/blog/3963-working-code-podcast-episode-005-monoliths-vs-microservices.htm?ref=daveabrock.com">a discussion on monoliths vs. microservices</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1722&ref=daveabrock.com">checks in on IdentityServer</a>.</li><li>The .NET Core Show <a href="https://dotnetcore.show/episode-67-blazor-in-action-with-chris-sainty/?ref=daveabrock.com">talks Blazor with Chris Sainty</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-178-identity-with-christos-matskas/?ref=daveabrock.com">talks to Christos Matskas about Microsoft Identity</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>The ON.NET Show <a href="https://www.youtube.com/watch?v=hbgPvjTJSLY&ref=daveabrock.com">inspects application metrics with dotnet-monitor</a>, <a href="https://www.youtube.com/watch?v=ef_TBD3nkmQ&ref=daveabrock.com">works on change notifications with Microsoft Graph</a>, and <a href="https://channel9.msdn.com/Shows/On-NET/Inspecting-application-metrics-with-dotnet-monitor?ref=daveabrock.com">inspects application metrics with dotnet-monitor</a>.</li><li>Scott Hanselman <a href="https://www.youtube.com/watch?v=vvpCnjyjTuU&ref=daveabrock.com">shows you what happens when after you enter a URL in your browser</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=FgoJt1c6R6U&ref=daveabrock.com">talk about migrating their site to Azure Blob Storage.</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2021/01/11/MikeBenkovichOnGitHubActionsAndVisualStudio.aspx?ref=daveabrock.com">David Giard talks to Mike Benkovich about GitHub Actions and Visual Studio</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ How to use configuration with C# 9 top-level programs ]]></title>
        <description><![CDATA[ In a C# 9 deep dive, we talk about how top-level programs work with status codes, async, arguments, and local functions. ]]></description>
        <link>https://www.daveabrock.com/2021/01/19/config-top-level-programs/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe85</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 18 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1615309662472-4ca77a77a189?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDM5fHxjb25maWd1cmF0aW9ufGVufDB8fHx8MTYxOTgzMzA2NQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>I’ve been working with <a href="https://daveabrock.com/2020/07/09/c-sharp-9-top-level-programs?ref=daveabrock.com">top-level programs in C# 9</a> quite a bit lately. When writing simple console apps in .NET 5, it allows you to remove the ceremony of a namespace and a <code>Main(string[] args)</code> method. It’s very beginner-friendly and allows developers to get going without worrying about learning about namespaces, arrays, arguments, and so on. While I’m not a beginner—although I feel like it some days—I enjoy using top-level programs to prototype things quickly.</p><p>With top-level programs, you can work with normal functions, use <code>async</code> and <code>await</code>, access command-line arguments, use local functions, and more. For example, here’s me working with some arbitrary strings and getting a random quote from the <a href="https://github.com/jamesseanwright/ron-swanson-quotes?ref=daveabrock.com#ron-swanson-quotes-api">Ron Swanson Quotes API</a>:</p><pre><code class="language-csharp">using System;
using System.Net.Http;

var name = "Dave Brock";
var weekdayHobby = "code";
var weekendHobby = "play guitar";
var quote = await new HttpClient().GetStringAsync("https://ron-swanson-quotes.herokuapp.com/v2/quotes");

Console.WriteLine($"Hey, I'm {name}!");
Console.WriteLine($"During the week, I like to {weekdayHobby} and on the weekends I like to {weekendHobby}.");
Console.WriteLine($"A quote to live by: {quote}");
</code></pre><h2 id="add-configuration-to-a-top-level-program">Add configuration to a top-level program</h2><p>Can we work with configuration with top-level programs? (Yes, <em>should we</em> is a different conversation, of course.)</p><p>To be clear, there are <a href="https://docs.microsoft.com/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0&ref=daveabrock.com">many, many ways to work with configuration</a> in .NET. If you’re used to it in ASP.NET Core, for example, you’ve most likely done it from constructor dependency injection, wiring up a <code>ServiceCollection</code> in your middleware, or using the <code>Options</code> pattern—so you may think you won’t be able to do it with top-level programs.</p><p>Don’t overthink it. Using the <code>ConfigurationBuilder</code>, you can easily use configuration with top-level programs.</p><p>Let’s create an <code>appsettings.json</code> file to replace our hard-coded values with configuration values.</p><pre><code class="language-json">{
    "Name": "Dave Brock",
    "Hobbies": {
        "Weekday": "code",
        "Weekend": "play guitar"
    },
    "SwansonApiUri": "https://ron-swanson-quotes.herokuapp.com/v2/quotes"
}
</code></pre><p>Then, make sure your project file has the following packages installed, and that the <code>appSettings.json</code> file is being copied to the output directory:</p><pre><code class="language-xml">  &lt;ItemGroup&gt;
    &lt;PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" /&gt;
    &lt;PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" /&gt;
    &lt;PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" /&gt;
  &lt;/ItemGroup&gt;

  &lt;ItemGroup&gt;
    &lt;None Update="appsettings.json"&gt;
      &lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt;
    &lt;/None&gt;
  &lt;/ItemGroup&gt;
</code></pre><p>In your top-level program, create a <code>ConfigurationBuilder</code> with the appropriate values:</p><pre><code class="language-csharp">var config = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddJsonFile("appsettings.json")
                 .Build();
</code></pre><p>With a <code>config</code> instance, you’re ready to simply read in your values:</p><pre><code>var name = config["Name"];
var weekdayHobby = config.GetSection("Hobbies:Weekday");
var weekendHobby = config.GetSection("Hobbies:Weekend");
var quote = await new HttpClient().GetStringAsync(config["SwansonApiUri"]);
</code></pre><p>And here’s the entire top-level program in action:</p><pre><code class="language-csharp">using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Net.Http;

var config = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddJsonFile("appsettings.json")
                 .Build();

var name = config["Name"];
var weekdayHobby = config.GetSection("Hobbies:Weekdays");
var weekendHobby = config.GetSection("Hobbies:Weekends");
var quote = await new HttpClient().GetStringAsync(config["SwansonApiUri"]);

Console.WriteLine($"Hey, I'm {name}!");
Console.WriteLine($"During the week, I like to {weekdayHobby.Value}" +
        $" and on the weekends I like to {weekendHobby.Value}.");
Console.WriteLine($"A quote to live by: {quote}");
</code></pre><h2 id="review-the-generated-code">Review the generated code</h2><p>When throwing this in the <a href="https://github.com/icsharpcode/ILSpy?ref=daveabrock.com">ILSpy decompilation tool</a>, you can see there’s not a lot of magic here. The top-level program is merely wrapping the code in a <code>Main(string[] args)</code> method and replacing our implicit typing:</p><pre><code class="language-csharp">using System;
using System.IO;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

[CompilerGenerated]
internal static class &lt;Program&gt;$
{
  private static async Task &lt;Main&gt;$(string[] args)
  {
    IConfigurationRoot config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
    string name = config["Name"];
    IConfigurationSection weekdayHobby = config.GetSection("Hobbies:Weekday");
    IConfigurationSection weekendHobby = config.GetSection("Hobbies:Weekend");
    string quote = await new HttpClient().GetStringAsync(config["SwansonApiUri"]);
    Console.WriteLine("Hey, I'm " + name + "!");
    Console.WriteLine("During the week, I like to " + weekdayHobby.Value + " and on the weekends I like to " + weekendHobby.Value + ".");
    Console.WriteLine("A quote to live by: " + quote);
  }
}
</code></pre><h2 id="wrap-up">Wrap up</h2><p>In this quick post, I showed you how to work with configuration in C# 9 top-level programs. We showed how to use a <code>ConfigurationBuilder</code> to read from an <code>appsettings.json</code> file, and we also reviewed the generated code.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Dev Discussions: Steve Sanderson ]]></title>
        <description><![CDATA[ We talk to Steve Sanderson, the creator of Blazor, about what&#39;s next. ]]></description>
        <link>https://www.daveabrock.com/2021/01/17/dev-discussions-steve-sanderson/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe84</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 16 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/steve-sanderson.jpg" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This is the full interview from my discussion with Steve Sanderson in my weekly (free!) newsletter, The .NET Stacks. Consider <a href="https://dotnetstacks.com/?ref=daveabrock.com">subscribing today</a>!</em></p><p>It seems like forever ago when, <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">at NDC Oslo in 2017</a>, Steve Sanderson showed off a new web UI framework with the caveat: “<em>an experiment, something for you to be amused by</em>.” By extending <a href="https://github.com/chrisdunelm/DotNetAnywhere?ref=daveabrock.com">Dot Net Anywhere</a> (DNA), Chris Bacon’s portable .NET runtime, on WebAssembly, he was able to load and run C# in the browser. In the browser!</p><p>Of course, this amusing experiment has grown <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor?ref=daveabrock.com">into Blazor</a>, a robust system for writing web UIs in C#. I was happy to talk to Steve Sanderson about his passions for the front-end web, how far Blazor has come, and what’s coming to Blazor in .NET 6.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/steve-sanderson-2.jpg" class="kg-image" alt="Steve Sanderson profile photo" loading="lazy" width="350" height="350"></figure><h2 id="what-geared-you-toward-the-front-end-web-over-other-tech">What geared you toward the front-end web, over other tech?</h2><p>It’s not that I’m personally more motivated by front-end web over other tech. I’m just as motivated by all kinds of other technology, whether that’s backend web stuff, or further out fields like ML, graphics, or games—even things like agriculture automation.</p><p>What I have found though is that my professional life has had more impact in front-end web than in other fields. I’m not certain why, but suspect it’s been an under-focused area. When I started my first software job in 2003, being able to do anything in a browser with JS was considered unusual, so it was pretty easy to exceed the state of the art then.</p><h2 id="my-front-end-experience-started-with-knockout-js-your-mvvm-front-end-framework-we-ve-come-a-long-away-since-then-for-sure-have-any-of-your-experience-and-learnings-from-knockout-impacted-your-work-on-blazor">My front-end experience started with Knockout.js, <a href="https://knockoutjs.com/?ref=daveabrock.com">your MVVM front-end framework</a>. We’ve come a long away since then, for sure. Have any of your experience and learnings from Knockout impacted your work on Blazor?</h2><p>Certainly. Knockout was my first critical-mass open source project, so that’s where I was forced to design APIs to account for how developers get confused and do things contrary to their own best interests, what to expect from the community, and where to draw the line about what features should be in or out of a library/framework.</p><h2 id="years-ago-you-probably-envisioned-what-blazor-could-be-has-it-met-its-potential-or-are-there-other-areas-to-focus-on">Years ago, you probably envisioned what Blazor could be. Has it met its potential, or are there other areas to focus on?</h2><p>We’re not there yet. If you go on YouTube and find the <a href="https://youtu.be/MiLAE6HMr10?t=1612&ref=daveabrock.com">first demo I ever did of Blazor at NDC Oslo in 2017</a>, you’ll see my original prototype had near-instant live reloading while coding, and the download size was really tiny. I still aspire to get the real version of Blazor to have those characteristics. Of course, the prototype had the advantage of only needing to do a tiny number of things—creating a production-capable version is 100x more work, which is why it hasn’t yet got there, but has of course exceeded the prototype vastly in more important ways.</p><p>Good news though is that in .NET 6 <a href="https://github.com/dotnet/aspnetcore/issues/5456?ref=daveabrock.com">we expect to ship</a> an even better version of live-updating-while-coding than I had in that first prototype, so it’s getting there!</p><h2 id="the-blazor-use-case-for-net-devs-is-quite-clear-do-you-see-blazor-reaching-a-lot-of-folks-in-the-javascript-community-i-m-thinking-of-angular-where-the-learning-curve-is-steep-or-do-you-see-blazor-s-impact-limited-to-the-net-ecosystem">The Blazor use case for .NET devs is quite clear. Do you see Blazor reaching a lot of folks in the JavaScript community (I’m thinking of Angular, where the learning curve is steep), or do you see Blazor’s impact limited to the .NET ecosystem?</h2><p>Longer term I think it depends on the fundamentals: download size and perf. With .NET 5, Blazor WebAssembly’s main selling point is the .NET code, which easily makes it the best choice of framework for a lot of .NET-centric teams, but on its own that isn’t enough to win over a JS-centric team.</p><p>If we can get Blazor WebAssembly to be faster than JS in typical cases (via AoT compilation, which is very achievable) and somehow simultaneously reduce download sizes to the point of irrelevance, then it would be very much in the interests of even strongly JS-centric teams to reconsider and look at all the other benefits of C#/.NET too.</p><h2 id="when-looking-at-aot-you-ll-see-increased-performance-but-a-larger-download-size-do-you-see-any-other-tradeoffs-developers-will-need-to-consider">When looking at AOT, you’ll see increased performance but a larger download size. Do you see any other tradeoffs developers will need to consider?</h2><p>The mixed-mode flavour of AOT, in which some of your code is interpreted and some is AOT, allows for a customizable tradeoff between size and speed, but also includes some subtleties like extra overhead when calling from AOT to interpreted code and vice-versa.</p><p>Also, when you enable AOT, your app’s publish time may go up substantially (maybe by 5-10 minutes, depending on code size) because the whole <a href="https://emscripten.org/?ref=daveabrock.com">Emscripten toolchain</a> just takes that long. This wouldn’t affect your daily development flow on your own machine, but likely means your CI builds could take longer.</p><h2 id="it-s-still-quite-impressive-to-see-the-entire-net-runtime-run-in-the-browser-for-blazor-web-assembly-that-comes-with-an-upfront-cost-as-we-know-i-know-that-the-blazor-team-has-done-a-ton-of-work-to-help-lighten-the-footprint-and-speed-up-performance-with-the-exception-of-aot-do-you-envision-more-work-on-this-do-you-see-a-point-where-it-ll-be-as-lightweight-as-other-leading-front-end-frameworks-or-will-folks-need-to-understand-it-s-a-cost-that-comes-with-a-full-framework-in-the-browser">It’s still quite impressive to see the entire .NET runtime run in the browser for Blazor Web Assembly. That comes with an upfront cost, as we know. I know that the Blazor team has done a ton of work to help lighten the footprint and speed up performance. With the exception of AOT, do you envision more work on this? Do you see a point where it’ll be as lightweight as other leading front-end frameworks, or will folks need to understand it’s a cost that comes with a full framework in the browser?</h2><p>The size of the .NET runtime isn’t ever going to reduce to near-zero, so JS-based microframeworks (whose size could be just a few KB) are always going to be smaller. We’re not trying to win outright based on size alone—that would be madness. Blazor WebAssembly is aimed to be maximally productive for developers while being small enough to download that, in very realistic business app scenarios, the download size shouldn’t be any reason for concern.</p><p>That said, it’s conceivable that new web platform features like <a href="https://developers.google.com/web/updates/2018/11/signed-exchanges?ref=daveabrock.com">Signed HTTP Exchanges</a> could let us smartly pre-load the .NET WebAssembly runtime in a browser in the background (directly from some Microsoft CDN) while you’re visiting a Blazor WebAssembly site, so that it’s instantly available at zero download size when you go to other Blazor WebAssembly sites. Signed HTTP Exchanges allow for a modern equivalent to the older idea of a cross-site CDN cache. We don’t have a definite plan about that yet as not all browsers have added support for it.</p><h2 id="i-know-that-you-aren-t-a-xamarin-expert-but-i-m-intrigued-by-blazor-mobile-bindings-do-you-see-there-being-convergence-between-maui-and-blazor-or-is-this-a-do-what-works-for-you-platform-decision">I know that you aren’t a Xamarin expert, but I’m intrigued by Blazor Mobile Bindings. Do you see there being convergence between MAUI and Blazor, or is this a “do what works for you” platform decision?</h2><p>Who says I’m not a Xamarin expert, huh? Well, OK, I admit it—I’m not.</p><p>Our ideas around MAUI are pretty broad and allow for a lot of different architecture and syntax choices, without having a definite confirmation yet about what exactly are the most first-class built-in options. So I don’t think any conclusion exists here yet.</p><h2 id="speaking-more-broadly-from-the-last-question-do-you-see-blazor-as-the-future-of-native-app-development-in-net-for-mobile-and-desktop-apps">Speaking more broadly from the last question: do you see Blazor as the future of native app development in .NET, for mobile and desktop apps?</h2><p>My guess is there will always be variety. .NET has always supported many different UI programming models (WinForms, WebForms, WPF, UWP, Xamarin, MVC, Razor Pages, Blazor, Unity). The idea that everything would converge on a single one true framework seems unlikely, because different customer groups have different goals and demands.</p><p>Blazor is perhaps the option that gives the widest reach across device types, as it’s obviously web-native, but can also target desktop and mobile apps via either web or native rendering within native app shells.</p><h2 id="when-looking-ahead-to-net-6-in-the-next-year-or-so-what-s-coming-with-blazor">When looking ahead to .NET 6, in the next year or so, what’s coming with Blazor?</h2><p>See our <a href="https://github.com/dotnet/aspnetcore/issues/27883?ref=daveabrock.com">published roadmap</a>. 😊</p><p><em>[Ed. Note: Fair enough. The heavy hitters include</em> <a href="https://github.com/dotnet/aspnetcore/issues/5466?ref=daveabrock.com"><em>AOT compilation</em></a><em>,</em> <a href="https://github.com/dotnet/aspnetcore/issues/5456?ref=daveabrock.com"><em>hot reload</em></a><em>,</em> <a href="https://github.com/dotnet/aspnetcore/issues/13452?ref=daveabrock.com"><em>global exception handling</em></a><em>, and</em> <a href="https://github.com/dotnet/aspnetcore/issues/11815?ref=daveabrock.com"><em>required parameters for components</em></a><em>.]</em></p><h2 id="does-blazor-hold-up-from-a-load-testing-perspective-would-it-support-amazon-like-scale">Does Blazor hold up from a load testing perspective? Would it support Amazon-like scale?</h2><p>Blazor Server or Blazor WebAssembly?</p><p>Blazor WebAssembly has the benefit of imposing no per-client runtime cost on the server—from the server’s perspective, it’s just some static content to transmit. So in that sense it inherently scales near-infinitely. But for a public-facing shopping cart app, you most likely want server-rendered HTML to maximise SEO and minimize the risk that any potential customers fail to use the site just because of the initial page load time.</p><p>Blazor Server is a more obvious choice for a public-facing shopping cart app. We know it scales well, and a typical cloud server instance can comfortably manage 20k very active concurrent users—the primary limitation is RAM, not CPU. I don’t personally know how many front-end servers are involved in serving Amazon’s pages or how many concurrent users they are dealing with. However I do know that virtually everybody building business web apps is operating at a vastly smaller scale than Amazon, and can likely estimate (to within an order of magnitude) how many concurrent users they want to plan for and thus what server capacity is needed.</p><h2 id="what-is-your-one-piece-of-programming-advice">What is your one piece of programming advice?</h2><p>When something isn’t working or behaves differently than you expected, don’t just keep changing things until it seems to work, as a lot of developers do. Make sure you figure out why it was doing what it was doing, otherwise you’re not really advancing your skills.</p><p><em>You can connect with Steve Sanderson</em> <a href="https://twitter.com/stevensanderson?ref=daveabrock.com"><em>on Twitter</em></a><em>.</em></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #32: 😎 SSR is cool again ]]></title>
        <description><![CDATA[ This week, we talk about SSR and Xamarin.Forms 5.0. ]]></description>
        <link>https://www.daveabrock.com/2021/01/16/dotnet-stacks-32/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe83</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 15 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-13.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Good morning and happy Monday! We’ve got a few things to discuss this week:</p><ul><li>The new/old hotness: HTML over the wire</li><li>Xamarin.Forms 5.0 released this week</li><li>Quick break: how to explaining C# string interpolation to the United States Senate</li><li>Last week in the .NET world</li></ul><h2 id="the-new-old-hotness-server-side-rendering">The new/old hotness: server-side rendering</h2><p>Over the holidays, I was intrigued by the release of <a href="https://hotwire.dev/?ref=daveabrock.com">the Hotwire project</a>, from the folks at Basecamp:</p><blockquote>Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire. This makes for fast first-load pages, keeps template rendering on the server, and allows for a simpler, more productive development experience in any programming language, without sacrificing any of the speed or responsiveness associated with a traditional single-page application.</blockquote><p>Between this and other tech such as Blazor Server, the “DOM over the wire” movement is in full force. It’s a testament to how bloated and complicated the front end has become.</p><p>Obviously, rendering partial HTML over the wire isn’t anything new at all—especially to us .NET developers—and it’s sure to bring responses like: <em>“Oh, you mean what I’ve been doing the last 15 years?”</em> As much as I enjoy the snark, it’s important to not write it off as the front-end community embracing what we’ve become comfortable with, as the technical details differ a bit—and we can learn from it. For example, it looks like instead of Hotwire working with DOM diffs over the wire, it streams partial updates over WebSocket while dividing complex pages into separate components, with an eye on performance. I wonder how Blazor Server would have been architected if this was released 2 years ago.</p><h2 id="xamarin-forms-5-0-released-this-week">Xamarin.Forms 5.0 released this week</h2><p>This week, the Xamarin team <a href="https://devblogs.microsoft.com/xamarin/xamarin-forms-5-0-is-here/?ref=daveabrock.com">released the latest stable release of Xamarin.Forms, version 5.0</a>, which will be supported through November 2022. There’s updates for App Themes, Brushes, and SwipeView, among other things. The team <a href="https://www.youtube.com/watch?v=DVE-orw3p0k&ref=daveabrock.com">had a launch party</a>. Also, David Ramel writes that this <a href="https://visualstudiomagazine.com/articles/2021/01/07/xamarin-forms-5.aspx?ref=daveabrock.com">latest version drops support for Visual Studio 2017</a>. Updates to Android and iOS are only delivered to 2019, and pivotal for getting the latest updates from Apple and Google.</p><p>2021 promises to be a big year for Xamarin, as they continue preparing to join .NET 6—as this November, Xamarin.Forms evolves into MAUI (the .NET Multi-Platform App UI). This means more than developing against iPhones and Android devices, of course. With .NET 6 this also includes native UIs for iOS, Android, and desktops. As David Ramel also writes, Linux <a href="https://visualstudiomagazine.com/articles/2021/01/05/maui.aspx?ref=daveabrock.com">will not be supported out of the gate and VS Code support will be quite limited</a>.</p><p>As he also writes, in a community standup David Ortinau clarifies that MAUI is not a rewrite.</p><blockquote>So my hope and expectation, depending on the complexity of your projects, is you can be up and going within days … It’s not rewrites – it’s not a rewrite – that’s probably the biggest message that I should probably say over and over and over again. You’re not rewriting your application.</blockquote><h2 id="quick-break-how-to-explain-c-string-interpolation-to-the-united-states-senate">Quick break: how to explain C# string interpolation to the United States Senate</h2><p>Did I ever think C# string interpolation would make it to the United States Senate? No, I most certainly did not. But last month, that’s what happened as former Cybersecurity and Infrastructure Security Agency (CISA) head Chris Krebs explained a bug:</p><blockquote>It’s on page 20 … it says ‘There is no permission to {0}’. … Something jumped out at me, having worked at Microsoft. … The election-management system is coded with the programming language called C#. There is no permission to {0}’ is placeholder for a parameter, so it may be that it’s just not good coding, but that certainly doesn’t mean that somebody tried to get in there a 0. They misinterpreted the language in what they saw in their forensic audit.</blockquote><p>It appears that the election auditors were scared by something like this:</p><pre><code>Console.WriteLine("There is no permission to {0}");
</code></pre><p>To us, we know it’s just a log statement that verifies permission checks are working. It should have been coded using one of the following lines of code:</p><pre><code class="language-csharp">Console.WriteLine("There is no permission to {0}", permission);
Console.WriteLine($"There is no permission to {permission}");
</code></pre><p>I’m available to explain string interpolation to my government for a low, low rate of $1000 an hour. All they had to do was ask.</p><figure class="kg-card kg-embed-card"><iframe width="560" height="315" src="https://www.youtube.com/embed/v0lCCRwRnOU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></figure><hr><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-4">🔥 The Top 4</h3><ul><li>Josef Ottosson <a href="https://josef.codes/polymorphic-deserialization-with-system-text-json/?ref=daveabrock.com">works with polymorphic deserialization with <code>System.Text.Json</code></a>.</li><li>Shahed Chowdhuri <a href="https://dev.to/dotnet/c-a-to-z-assignment-with-init-only-setters-12mo?ref=daveabrock.com">works with init-only setters in C# 9</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/entity-framework-core-5-interceptors?ref=daveabrock.com">writes about EF Core 5 interceptors</a>.</li><li>Over at the AWS site, the folks at DraftKings <a href="https://aws.amazon.com/blogs/modernizing-with-aws/modernizing-legacy-net-applications-draftkings-principles-for-success/?ref=daveabrock.com">have a nice read about modernizing with .NET Core and AWS</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>WinUI 3 Preview 3 <a href="https://devblogs.microsoft.com/pax-windows/winui-3-preview-3?ref=daveabrock.com">has been released</a>.</li><li>David Ortinau <a href="https://devblogs.microsoft.com/xamarin/xamarin-forms-5-0-is-here?ref=daveabrock.com">announces the arrival of Xamarin.Forms 5.0</a>.</li><li>Microsoft Learn <a href="https://docs.microsoft.com/learn/modules/intro-to-python?ref=daveabrock.com">has a new module on learning Python</a>.</li><li>James Newton-King <a href="https://docs.microsoft.com/aspnet/core/grpc/code-first?view=aspnetcore-5.0&ref=daveabrock.com">releases a new Microsoft doc, <em>Code-first gRPC services and clients with .NET</em></a>.</li><li>Phillip Carter brings attention <a href="https://docs.microsoft.com/dotnet/fsharp/style-guide/conventions?ref=daveabrock.com">to a living F# coding conventions document</a>.</li><li>Patrick Svensson <a href="https://twitter.com/firstdrafthell/status/1348303900651249664?ref=daveabrock.com">releases version 0.37 of <code>Spectre.Console</code></a>.</li><li>The Azure SDK team released new .NET packages to simplify migrations using <code>Newtonsoft.Json</code> and/or <code>Microsoft.Spatial</code>.</li><li>The EF Core team releases <code>EFCore.NamingConventions</code> 5.0.1, which fixes issues with owned entities and table splitting in 5.0.0.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>Chris Noring introduces <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/learn-web-dev-with-these-24-lessons-on-github/ba-p/2033829?ref=daveabrock.com">GitHub’s web dev for beginners tutorials</a>.</li><li>Niels Swimberghe rolls out two utilities written in Blazor: a<a href="https://swimburger.net/blog/dotnet/introducing-online-gzip-decompressor?ref=daveabrock.com"> GZIP compressor/decompressor</a>, and <a href="https://newguids.swimburger.net/?ref=daveabrock.com">a .NET GUID generator</a>.</li><li>ErikEJ <a href="https://erikej.github.io/efcore/2021/01/05/efcore-5-resources.html?ref=daveabrock.com">writes about some free resources for EF 5</a>.</li><li>The Xamarin community standup <a href="https://www.youtube.com/watch?v=DVE-orw3p0k&ref=daveabrock.com">is a launch party for Xamarin.Forms 5</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=oX2COO_1iOM&ref=daveabrock.com">talks to co-host David Pine about his localization project</a>.</li><li>Shahed Chowdhuri <a href="https://wakeupandcode.com/dotnet5-blazor-2021/?ref=daveabrock.com">previews a new C# A-Z project and a Marvel cinematic visualization app</a>.</li><li>Chris Woodruff kicks of an <a href="https://t.co/BnfpqTR0mp?amp=1&ref=daveabrock.com">ASP.NET 5 Web API blog series</a>.</li><li>VS Code Day <a href="https://t.co/2ZVOzfkQSR?amp=1&ref=daveabrock.com">is slated for January 27</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Peter Vogel <a href="https://visualstudiomagazine.com/articles/2021/01/06/blazor-lists.aspx?ref=daveabrock.com">writes about displaying lists efficiently in Blazor</a>.</li><li>Over at Code Maze, <a href="https://code-maze.com/api-gateway-pattern-dotnet-encapsulate-microservices/?ref=daveabrock.com">using the API gateway pattern in .NET to encapsulate microservices</a>.</li><li>David Fowler notes that <a href="https://github.com/dotnet/runtime/issues/31088?ref=daveabrock.com#issuecomment-754854011">web socket compression is coming to .NET 6</a>.</li><li>Chris Noring <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/learn-how-you-can-manage-configuration-in-asp-net/ba-p/2033895?ref=daveabrock.com">manages configuration in ASP.NET Core</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/how-to-sign-in-with-google-angular-aspnet-webapi/?ref=daveabrock.com">signs in with Google using Angular and ASP.NET Core Web API</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2021/01/05/azure-ad-access-token-lifetime-policy-management-in-asp-net-core/?ref=daveabrock.com">works with Azure AD access token lifetime policy management in ASP.NET Core</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/01/02/viewing-server-variables-in-asp-net-core?ref=daveabrock.com">views server variables in ASP.NET Core</a>.</li><li>Sahan Serasinghe <a href="https://dev.to/sahan/understanding-websockets-with-asp-net-core-g94?ref=daveabrock.com">writes about using Web Sockets with ASP.NET Core</a>.</li></ul><h3 id="-the-net-platform">🥅 The .NET platform</h3><ul><li>Richard Reedy <a href="https://www.telerik.com/blogs/dotnet-worker-service-working-hard-so-you-dont-have-to?ref=daveabrock.com">talks about the Worker Service in .NET Core</a>.</li><li>Marco Minerva <a href="https://marcominerva.wordpress.com/2021/01/04/developing-desktop-applications-with-net-5-0/?ref=daveabrock.com">develops desktop apps with .NET 5</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/activitysource-and-listener-in-net-5?ref=daveabrock.com">works with ActivitySource and ActivityListener in .NET 5</a>.</li><li>Nikola Zivkovic <a href="https://rubikscode.net/2021/01/04/machine-learning-with-ml-net-introduction/?ref=daveabrock.com">introduces machine learning with ML.NET</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/missing-files-in-multi-targeted-project?ref=daveabrock.com">works with missing files in a multi-targeted project</a>.</li><li>Stefan Koell writes about <a href="https://code4ward.net/2021/01/09/net-5-adventure-crossgen2/?ref=daveabrock.com">migrating Royal TS from WinForms to .NET 5</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/auto-assigning-issues-using-a-github-action/?ref=daveabrock.com">auto-assigns issues using a GitHub Action</a>.</li><li>Richard Reedy <a href="https://www.telerik.com/blogs/building-chatbot-to-order-pizza?ref=daveabrock.com">builds a chatbot to order a pizza</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2021/01/05/azure-bot-service-image-emotion-api?ref=daveabrock.com">uses the Microsoft Bot Framework to analyze emotion with the Azure Face API</a>.</li><li>Jonathan Channon <a href="https://www.softwarepark.cc/blog/2021/1/8/using-gcp-cloud-functions-with-f?ref=daveabrock.com">uses GCP Cloud Functions with F#</a>.</li><li>Justin Yoo <a href="https://dev.to/azure/eventgrid-subscription-to-custom-topic-using-azure-cli-130b?ref=daveabrock.com">writes about using Azure EventGrid</a>.</li><li>Mark Heath <a href="https://markheath.net/post/bulk-upload-azure-cli?ref=daveabrock.com">writes about bulk uploading files to Azure Blob Storage with the Azure CLI</a>.</li><li>Daniel Krzyczkowski <a href="https://daniel-krzyczkowski.github.io/Cars-Island-ASP-NET-Core-API-Secured-By-Azure-AD-B2C/?ref=daveabrock.com">continues his series on writing an ASP.NET Core API secured by Azure AD B2C</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2021/01/01/azure-service-bus-scheduled-message-delivery?ref=daveabrock.com">schedules message delivery with Azure Service Bus</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2021/Jan/05/Blank-Zero-Values-in-CSharp-Number-Format-Strings?ref=daveabrock.com">works with blank zero values in .NET number format strings</a>.</li><li>David McCarter <a href="https://www.c-sharpcorner.com/article/analyzing-code-for-issues-in-net-5/?ref=daveabrock.com">analyzes code for issues in .NET 5</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/play-audio-files-with-net?ref=daveabrock.com">plays audio files with .NET</a>.</li><li>Daniel Bachler talks about <a href="https://danielbachler.de/2020/12/23/what-i-wish-i-knew-when-learning-fsharp.html?ref=daveabrock.com">what he wishes he knew when learning F#</a>.</li><li>Michał Niegrzybowski writes about <a href="https://www.mnie.me/webrtcandably?ref=daveabrock.com">signaling in WebRTC with Ably and Fable</a>.</li><li>Mark-James McDougall talks about <a href="https://markjames.dev/2021-01-04-why-learning-fsharp-2021/?ref=daveabrock.com">why he’s learning F# in 2021</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Jason Robert <a href="https://espressocoder.com/2021/01/05/creating-a-serverless-docker-image/?ref=daveabrock.com">creates a serverless Docker image</a>.</li><li>Stephen Cleary <a href="https://blog.stephencleary.com/2021/01/asynchronous-messaging-1-basic-distributed-architecture.html?ref=daveabrock.com">kicks off a series around asynchronous messaging</a>.</li><li>Michał Białecki <a href="https://www.michalbialecki.com/2021/01/07/useful-sql-statements-when-writing-ef-core-5-migrations?ref=daveabrock.com">recaps useful SQL statements when writing EF Core migrations</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/splitting-up-a-monolith-into-microservices/?ref=daveabrock.com">splits up a monolith into microservices</a>.</li><li>Frank Boucher <a href="http://www.frankysnotes.com/2021/01/how-to-create-continuous-integration.html?ref=daveabrock.com">creates a CI/CD deployment solution for a Docker project</a>.</li><li>Alex Orlov writes about <a href="https://mailbeenet.wordpress.com/2020/11/10/use-tls-1-3-with-mailbee-net-objects/?ref=daveabrock.com">using TLS 1.3 for IMAP and SMTP connections through Mailbee.NET</a>.</li><li>Brad Beggs <a href="https://dev.to/brad_beggs/vs-code-vertical-rulers-for-prettier-code-3gp3?ref=daveabrock.com">writes about using vertical rulers in VS Code</a>.</li><li>Tim Cochran <a href="https://martinfowler.com/articles/developer-effectiveness.html?ref=daveabrock.com">writes about maximizing developer effectiveness</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2021/01/05/maui.aspx?ref=daveabrock.com">writes how Xamarin.Forms won’t be on Linux or VS Code for MAUI in .NET 6</a>, and also <a href="https://visualstudiomagazine.com/articles/2021/01/07/xamarin-forms-5.aspx?ref=daveabrock.com">mentions that Xamarin.Forms 5 is dropping Visual Studio 2017 support</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/xamarin-essentials-features-advantages-benefits?ref=daveabrock.com">writes about Xamarin Essentials</a>.</li><li>Anbu Mani <a href="https://xmonkeys360.com/2021/01/04/xamarin-forms-infinite-scroll-listview-lazy-loading/?ref=daveabrock.com">works with infinite scrolling in Xamarin.Forms</a>.</li><li>Matthew Robbins <a href="https://www.mfractor.com/blogs/news/embedding-a-javascript-interpreter-into-xamarin-apps-with-jint?ref=daveabrock.com">embeds a JS interpreter into Xamarin apps with Jint</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>Scott Hanselman <a href="https://hanselminutes.simplecast.com/episodes/living-through-2020-as-a-remote-developer-with-amanda-silver-28t79VXg?ref=daveabrock.com">talks to Amanda Silver about living through 2020 as a remote developer</a>.</li><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-177-f-sharp-and-functional-programming-with-phillip-carter/?ref=daveabrock.com">talks with Phillip Carter about F# and functional programming</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/sam-nasr-on-sql-server-for-developers-episode-122?ref=daveabrock.com">talks with Sam Nasr about SQL Server for developers</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Azure-Application-Insights-Profiler?ref=daveabrock.com">talks about the Azure App Insights Profiler</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=gEXVfqyRADU&ref=daveabrock.com">talk with Andrew Stanton-Nurse</a>.</li><li>Gerald Versluis <a href="https://www.youtube.com/watch?v=k-eg3gcSMSU&ref=daveabrock.com">secures a Xamarin app with fingerprint or face recognition</a>.</li><li>James Montemagno <a href="https://www.youtube.com/watch?v=GLfR2uosoSw&ref=daveabrock.com">makes another Xamarin.Forms 101 video</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2021/01/04/JavierLozanoOnVirtualConferences.aspx?ref=daveabrock.com">David Giard talks to Javier Lozano about virtual conferences</a>.</li><li>Jeff Fritz works on <a href="https://www.youtube.com/watch?v=0AhIXUqfXTo&ref=daveabrock.com">ASP.NET Core MVC</a> and also <a href="https://www.youtube.com/watch?v=Y_hTutN7yOw&ref=daveabrock.com">APIs with ASP.NET Core</a>.</li><li>ON.NET discusses <a href="https://www.youtube.com/watch?v=C_d6y5OMtMs&ref=daveabrock.com">cross-platform .NET development with OmniSharp</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Build a search-as-you-type box ]]></title>
        <description><![CDATA[ In this post, we build a quick search box that filters our images. ]]></description>
        <link>https://www.daveabrock.com/2021/01/14/blast-off-blazor-search-box/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe82</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Wed, 13 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1586769852836-bc069f19e1b6?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fHNlYXJjaHxlbnwwfHx8fDE2MTk4MzMyMzc&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>, <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolated our service dependencies</a>, worked on <a href="https://daveabrock.com/2020/12/13/blast-off-blazor-cosmos?ref=daveabrock.com">hosting our images over Azure Blob Storage and Cosmos DB</a>, <a href="https://daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery?ref=daveabrock.com">built a responsive image gallery</a>, and <a href="https://daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm?ref=daveabrock.com">implemented prerendering</a>.</p><p>With a full result set from Cosmos DB, in this post we’ll build a quick search box. While I was originally thinking I should execute queries against our database, I then thought: <em>You dummy, you already have the data, just filter it</em>. My inner voice doesn’t always offer sage advice, but it did this time.</p><p>Anyway, here’s how it’ll look.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/search-box.png" class="kg-image" alt="Our search box" loading="lazy" width="2000" height="815" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/search-box.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/search-box.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/search-box.png 1600w, https://www.daveabrock.com/content/images/2021/05/search-box.png 2042w" sizes="(min-width: 720px) 720px"></figure><p>You’ve likely noticed the absence of a search button. This will be in the “search-as-you-type” style, as results will get filtered based on what the user types. It’s a lot less work than you might think.</p><p>This post covers the following content.</p><ul><li><a href="#the-easy-part-our-filtering-logic">The “easy” part: our filtering logic</a></li><li><a href="#understand-data-binding">Understand data binding</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="the-easy-part-our-filtering-logic">The “easy” part: our filtering logic</h2><p>In very simplistic terms, here’s what we’ll do: a user will type some text in the search box, and we’ll use a LINQ query to filter it. Then, we’ll display the filtered results.</p><p>In <code>Images.razor.cs</code>, we’ll add <code>SearchText</code>. This field captures what the user enters. We’ll take that string, and see if we have any items that have a part of the string in the <code>Title</code>. We’ll want to make sure to initialize it to an empty string. That way, if nothing is entered, we’ll display the whole result set.</p><pre><code class="language-csharp">public string SearchText = "";
</code></pre><p>Then, I’ll include a <code>FilteredImages</code> field. This will return a filtered <code>List&lt;Image&gt;</code> that uses the LINQ query in question to filter based on the <code>SearchText</code>.</p><pre><code class="language-csharp">List&lt;Image&gt; FilteredImages =&gt; ImageList.Where(
    img =&gt; img.Title.ToLower().Contains(SearchText.ToLower())).ToList();
</code></pre><p>This part is relatively simple. We can do this in any type of app—Blazor, Web API, MVC, whatever. The power of Blazor is how we can leverage data binding to “connect” the data with our components to synchronize them and update our app accordingly. Let’s first understand data binding as a general concept.</p><h2 id="understand-data-binding">Understand data binding</h2><p>Data binding is not unique to Blazor. It’s essential to virtually all single-page application (SPA) libraries and frameworks. You can’t get away from displaying, updating, and receiving data.</p><p>The simplest example is with <em>one-way binding</em>. As inferred from the name, this means data updates only flow in one direction. In these cases, the application is responsible for handling the data. The gist: you have some data, an event occurs, and the data changes. There’s no need for a user to control the data yet.</p><p>In terms of events, by far the most common is a button click in Blazor:</p><pre><code class="language-csharp">&lt;p&gt;@TimesClicked&lt;/p&gt;

&lt;button @onclick="UpdateTimesClicked"&gt;Update Click Count&lt;/button&gt;

@code {
    private int TimesClicked { get; set; } = 1;

    private void UpdateTimesClicked()
    {
        TimesClicked++;
    }
}
</code></pre><p>In this example the <code>TimesClicked</code> is bound to the component with the <code>@</code> symbol. When a user clicks a button, the value changes—and, because an event handler was executed, Blazor triggers a re-render for us. Don’t let the simplicity of one-way binding fool you: in many cases, it’s all you need.</p><p>Whenever we need input from a user, we need to track that data and also bind it to a field. In our case, we need to know what the user is typing, store it in <code>SearchText</code>, and execute filtering logic as it changes. Because it needs to flow in both directions, we need to use <em>two-way binding</em>. For ASP.NET Core in particular, <a href="https://docs.microsoft.com/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0&ref=daveabrock.com">data binding involves</a> … binding … a <code>@bind</code> HTML element with a field, property, or Razor expression.</p><h3 id="understand-how-bind-and-bind-value-work">Understand how @bind and @bind-value work</h3><p>In the ASP.NET Core <a href="https://docs.microsoft.com/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0&ref=daveabrock.com">documentation for Blazor data binding</a>, this line should catch your eye:</p><blockquote>When one of the elements loses focus, its bound field or property is updated.</blockquote><p>In this case <code>@bind</code> works with an <code>onchange</code> handler after the input loses focus (like when a user tabs out). However, that’s not what we want. We want updates to occur as a user is typing and the ability to control which event triggers an update. After all, we don’t want to wait for a user to lose focus (and patience). Instead, we can use <code>@bind-value</code>. When we use <code>@bind-value:event="event"</code>, we can specify a valid event like <code>oninput</code>, <code>keydown</code>, <code>keypress</code>, and so on. In our case, we’ll want to use <code>oninput</code>, or whenever the user types something.</p><p>Don’t believe me? That’s fine, we’re only Internet friends, I understand. You can go check out the compiled components in your project’s <code>obj/Debug/net5.0/Razor/Pages</code> directory. Here’s how my <code>BuildRenderTree</code> method looks with <code>@bind-value</code> (pay attention to the last line):</p><pre><code class="language-csharp">protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
    __builder.OpenElement(0, "div");
    __builder.AddAttribute(1, "class", "text-center bg-blue-100");
    __builder.AddAttribute(2, "b-bc0k7zrx0q");
    __builder.OpenElement(3, "input");
    __builder.AddAttribute(4, "class", "border-4 w-1/3 rounded m-6 p-6 h-8\r\n               border-blue-300");
    __builder.AddAttribute(5, "placeholder", "Search by title");
    __builder.AddAttribute(6, "value", Microsoft.AspNetCore.Components.BindConverter.FormatValue(SearchText));
    __builder.AddAttribute(7, "oninput", Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value =&gt; SearchText = __value, SearchText));
    // and more ...
}
</code></pre><h3 id="put-it-together">Put it together</h3><p>When we set <code>@bind-value</code> to <code>SearchText</code> and <code>@bind-value:event</code> to <code>oninput</code>, we’ll be in business. Here’s how we’ll wire up the search box:</p><pre><code>&lt;div class="text-center bg-blue-100"&gt;
    &lt;input class="border-4 w-1/3 rounded m-6 p-6 h-8
               border-blue-300" @bind-value="SearchText"
           @bind-value:event="oninput" placeholder="Search by title" /&gt;
&lt;/div&gt;
</code></pre><p>Finally, as we’re iterating through our images, pass in <code>FilteredImages</code> instead:</p><pre><code class="language-csharp">@foreach (var image in FilteredImages)
{
    &lt;ImageCard ImageDetails="image" /&gt;
}
</code></pre><p>So now, here’s the entire code for our <code>Images</code> component:</p><pre><code class="language-html">@page "/images"
&lt;div class="text-center bg-blue-100"&gt;
    &lt;input class="border-4 w-1/3 rounded m-6 p-6 h-8
               border-blue-300" @bind-value="SearchText"
           @bind-value:event="oninput" placeholder="Search by title" /&gt;
&lt;/div&gt;

@if (!ImageList.Any())
{
    &lt;p&gt;Loading some images...&lt;/p&gt;
}
else
{
    &lt;div class="p-2 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3"&gt;
        @foreach (var image in FilteredImages)
        {
            &lt;ImageCard ImageDetails="image" /&gt;
        }
    &lt;/div&gt;
}
</code></pre><p>And the <code>Images</code> partial class:</p><pre><code class="language-csharp">using BlastOff.Shared;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlastOff.Client.Pages
{
    partial class Images : ComponentBase
    {
        public IEnumerable&lt;Image&gt; ImageList { get; set; } = new List&lt;Image&gt;();

        public string SearchText = "";

        [Inject]
        public IImageService ImageService { get; set; }

        protected override async Task OnInitializedAsync()
        {
            ImageList = await ImageService.GetImages(days: 70);
        }

        List&lt;Image&gt; FilteredImages =&gt; ImageList.Where(
            img =&gt; img.Title.ToLower().Contains(SearchText.ToLower())).ToList();
    }
}

</code></pre><p>Here’s the search box in action. Look at us go.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">It&#39;s so fast! Trying to remember the pains I&#39;ve had in my career implementing typeahead, and in <a href="https://twitter.com/hashtag/Blazor?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#Blazor</a> it&#39;s super simple with data binding on change. <a href="https://t.co/zRjOmeUXCu?ref=daveabrock.com">pic.twitter.com/zRjOmeUXCu</a></p>&mdash; Dave Brock (@daveabrock) <a href="https://twitter.com/daveabrock/status/1349882727621865473?ref_src=twsrc%5Etfw&ref=daveabrock.com">January 15, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="wrap-up">Wrap up</h2><p>In this post, I wrote how to implement a quick “type-as-you-go” search box in Blazor. We wrote filtering logic, understood how data binding works, compared <code>@bind</code> and <code>@bind-value</code> in Blazor, and finally put it all together.</p><p>There’s certainly more we can do here—things like debouncing come in handy when we want to control (and sometimes delay) how often searches are executed. I’m less concerned because this is all executed on the client, but would definitely come into play when we want to limit excessive trips to the database.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #31: 🥳 10 things to kick off &#x27;21 ]]></title>
        <description><![CDATA[ This week, we kick off 2021 with a busy issue. ]]></description>
        <link>https://www.daveabrock.com/2021/01/09/dotnet-stacks-31/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe81</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 08 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-14.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter, The .NET Stacks. It was originally sent to subscribers on January 4, 2021. Subscribe at the bottom of this post to get the content right away!</em></p><p>Well, friends, our dream has finally come true: 2020 is now over.</p><p>I hope your 2021 is off to a great start, and also hope you and your families were able to enjoy the holidays. I was lucky enough to take a break. I kept busy: hung out with the kids, watched a bunch of bad TV, worked out (which included shoveling snow three times; thanks, Wisconsin), tried out streaming, hacked around on some side projects, and generally just had fun with the time off.</p><p>This week, let’s play catch up. Let’s run through 10 things to get us ready for what’s to come in 2021. Ready?</p><hr><p>With .NET 5 out to the masses, we’re beginning to get past a lot of the novelty of source generators—there’s some great use cases out there. (If you aren’t familiar, source generators are a piece of code that runs during compilation and can inspect your app to produce additional files that are compiled together from the rest of your code.)</p><p>To that end, Tore Nestenius writes about a source generator that automatically generates an API for a system that <a href="https://www.edument.se/en/blog/post/net-5-source-generators-mediatr-cqrs?ref=daveabrock.com">uses the MediatR library and the CQRS pattern</a>. What a world.</p><p>Expect to see a lot of innovation with source generators this year.</p><hr><p>In my <em>Blast Off with Blazor</em> blog series, I’ve been using Tailwind CSS to mark up my components—you can see it in action where I <a href="https://daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery?ref=daveabrock.com">build a responsive image gallery</a>. Instead of Bootstrap, which can give you previously styled UI components, it’s a utility-first library that allows you to style classes in your markup. You can avoid the hassle of overriding stylesheets when things aren’t to your liking.</p><p>To be clear, you may cringe at first when you see this. (I know I did.)</p><pre><code class="language-html">&lt;div class="m-6 rounded overflow-hidden shadow-lg"&gt;
    &lt;img class="w-full h-48 object-cover" src="@ImageDetails.Url" alt="@ImageDetails.Title" /&gt;
    &lt;div class="p-6"&gt;
        &lt;div class="flex items-baseline"&gt;
            &lt;!-- stuff --&gt;
        &lt;/div&gt;
        &lt;h3 class="mt-1 font-semibold text-2xl leading-tight truncate"&gt;@ImageDetails.Title&lt;/h3&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre><p>Once you get used to it, though, you’ll begin to see its power. Adam Wathan, the creator of Tailwind, <a href="https://adamwathan.me/css-utility-classes-and-separation-of-concerns/?ref=daveabrock.com">wrote a piece</a> that helps you get over the initial visceral reaction.</p><hr><p>Over the weekend, I <a href="https://twitter.com/daveabrock/status/1345413697028685824?ref=daveabrock.com">asked this question</a>:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">What would you be doing for a living if computers or software didn&#39;t exist? I literally have no idea.</p>&mdash; Dave Brock (@daveabrock) <a href="https://twitter.com/daveabrock/status/1345413697028685824?ref_src=twsrc%5Etfw&ref=daveabrock.com">January 2, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>This led to entertaining answers. A lot of people talked about going professional with their hobbies, like with music and art. I also found it interesting how many answers had parallels to programming, like being a cook, architecting buildings, and building and maintaining things.</p><hr><p>What <em>can’t</em> you do with GitHub Actions? David Pine wrote an Action that <a href="https://devblogs.microsoft.com/dotnet/localize-net-applications-with-machine-translation/?ref=daveabrock.com">performs machine-translations from Azure Cognitive Services for .NET localization</a>. Tim Heuer <a href="https://timheuer.com/blog/use-github-actions-for-bulk-resolve-issues/?ref=daveabrock.com">used GitHub Actions for bulk resolving</a>. Of course, you <a href="https://github.com/sdras/awesome-actions?ref=daveabrock.com">could go on and on</a>.</p><p>The main use case is clear: workflows centered around your GitHub deployments, which goes hand-in-hand with it being <a href="https://daveabrock.com/2020/08/15/dotnet-stacks-12?ref=daveabrock.com">the long-term solution to the Azure DevOps platform</a>. My prediction is that in 2021, the feature gap between Azure DevOps and GitHub Actions will narrow significantly.</p><p>The success of GitHub Actions is sure to blur the lines between all the Microsoft solutions—between Azure Functions, Actions, and WebJobs, for example. While the main use case for Actions is deployment workflows, it’s hard to beat an app backed by a quick YAML file.</p><hr><p>We’ve talked about <code>System.Text.Json</code> quite a few times before. The gist from those posts: <code>System.Text.Json</code> is a new-ish native JSON serialization library for .NET Core. It’s fast and performant but isn’t as feature-rich as <code>Newtonsoft.Json</code> (<a href="https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0&ref=daveabrock.com#table-of-differences-between-newtonsoftjson-and-systemtextjson">this table gets worse</a> the more you scroll)—so if you’re already using Newtonsoft, stick with it unless you’ve got advanced performance considerations.</p><p>A few days after Christmas, Microsoft’s Layomi Akinrinade <a href="https://devblogs.microsoft.com/dotnet/whats-next-for-system-text-json/?ref=daveabrock.com">provided an update</a> on <code>System.Text.Json</code>. .NET 5 was a big release for the library, as they pushed a lot of updates that brought more Newtonsoft-like functionality: <a href="https://devblogs.microsoft.com/dotnet/whats-next-for-system-text-json/?ref=daveabrock.com#new-features">you’ll see</a> the ability to deserialize paramterized constructors, conditionally ignoring properties (thank you), C# record types, and constructors that take serialization defaults.</p><p>With .NET 6, Microsoft plans to “address the most requested features that help drive <code>System.Text.Json</code> to be a viable choice for the JSON stack in more .NET applications.” This is after writing (in the same post) that in .NET Core 3.0, “we made <code>System.Text.Json</code> the default serializer for ASP.NET Core because we believe it’s good enough for most applications.” So, that’s interesting. With Newtonsoft expected to <a href="https://www.nuget.org/packages?ref=daveabrock.com">top the NuGet charts</a> for the foreseeable future, it’s nice to see Microsoft understanding there’s much work to do, still, to encourage folks to move over to their solution.</p><hr><p>Egil Hansen, the man behind bUnit—the Blazor component testing library—describes how component vendors can make their components easily testable with a one-liner. Developers can now call an extension method based on bUnit’s <code>TestContext</code> that users can call before kicking off tests. The extension method can then be published as a NuGet package with a version matching the compatible library.</p><p>Check out <a href="https://twitter.com/egilhansen/status/1343169295593963521?ref=daveabrock.com">the Twitter thread for details</a>.</p><hr><p>Did you know that you can target attributes in C# 9 records using a prefix of <code>property:</code> or <code>field:</code>? You do now.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The always smart <a href="https://twitter.com/jnm236?ref_src=twsrc%5Etfw&ref=daveabrock.com">@jnm236</a> pointed out that you can target attributes on <a href="https://twitter.com/hashtag/csharp?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#csharp</a> <a href="https://twitter.com/hashtag/records?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#records</a> using a prefix of “property:” or “field:”<br><br>This is a pretty cool feature of records!  <br><br>Also, follow <a href="https://twitter.com/jnm236?ref_src=twsrc%5Etfw&ref=daveabrock.com">@jnm236</a>. <a href="https://t.co/wUvD2Dca6k?ref=daveabrock.com">pic.twitter.com/wUvD2Dca6k</a></p>&mdash; Khalid The Fungi 🍄 (@buhakmeh) <a href="https://twitter.com/buhakmeh/status/1341483189613813762?ref_src=twsrc%5Etfw&ref=daveabrock.com">December 22, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><p>The .NET Foundation released their November/December 2020 update <a href="https://dotnetfoundation.org/blog/2020/12/15/blog/posts/net-foundation-november-december-2020-update?ref=daveabrock.com">just before the holidays</a>. There’s a community survey you can fill out, <a href="https://dotnetfoundation.org/about/survey?utm_source=dotnetfdn&utm_medium=newsletter">that’s available until the end of March</a>. They’ve also launched a <a href="https://dotnetfoundation.org/community/speakers?ref=daveabrock.com">speaker directory</a>.</p><hr><p>Speaking of the .NET Foundation, tonight I watched board member Shawn Wildermuth’s new film, <em>Hello World</em>. It begins as a love letter to our industry, then takes a sobering look at our diversity and inclusion issues. It’s a wonderful film that everyone should see. It’s a cheap rental (<a href="https://helloworldfilm.com/?ref=daveabrock.com">check out the site to see where to rent it</a>)—and once there you can also help support organizations that are helping push our industry to where it should be.</p><hr><p>As you may or may not have noticed, the Azure SDKs have gotten a facelift. During our break, Jeffrey Richter <a href="https://devblogs.microsoft.com/azure-sdk/architecture/?ref=daveabrock.com">wrote about its architecture</a>.</p><p>Crucial to the SDK design—and most importantly, crucial to <em>me</em>—is that retry and cancellation mechanisms are built in. Additionally, you can implement your own policies in their pipeline (think ASP.NET Core middleware) for things like caching and mocking. Right on cue, Pavel Krymets <a href="https://devblogs.microsoft.com/azure-sdk/unit-testing-and-mocking/?ref=daveabrock.com">writes about unit testing and mocking with the .NET SDKs</a>.</p><hr><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Tore Nestenius <a href="https://www.edument.se/en/blog/post/net-5-source-generators-mediatr-cqrs?ref=daveabrock.com">uses source generators with C# 9 and .NET 5 for MediatR and CQRS</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/pre-render-blazor-webassembly-at-build-time-to-optimize-for-search-engines?ref=daveabrock.com">pre-renders Blazor Web Assembly at build time for SEO</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/should-i-use-self-contained-or-framework-dependent-publishing-in-docker-images/?ref=daveabrock.com">compares using self-contained or framework-dependent publishing in Docker images</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Nat Friedman <a href="https://github.blog/2020-12-17-no-cookie-for-you/?ref=daveabrock.com">writes how GitHub removed all cookie banners from GitHub</a>.</li><li>The Uno Platform <a href="https://platform.uno/blog/top-10-uno-platform-developments-to-look-forward-to-in-2021/?ref=daveabrock.com">writes about the developments to look forward to in 2021</a>.</li><li>Tobias Ahlin <a href="https://github.blog/2020-12-21-how-we-built-the-github-globe/?ref=daveabrock.com">discusses how the GitHub globe was built</a>.</li><li>Google Chrome <a href="https://www.bleepingcomputer.com/news/google/google-chrome-is-testing-larger-cache-sizes-to-increase-performance/?ref=daveabrock.com">is testing larger cache sizes for performance</a>.</li><li>Microsoft Learn has <a href="https://docs.microsoft.com/learn/paths/create-serverless-applications?ref=daveabrock.com">learning path for creating serverless applications</a>.</li><li>Layomi Akinrinade <a href="https://devblogs.microsoft.com/dotnet/whats-next-for-system-text-json?ref=daveabrock.com">writes about what’s next for System.Text.Json</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Maarten Balliauw <a href="https://blog.jetbrains.com/dotnet/2020/12/17/catch-up-with-2020-s-net-community-webinars/?ref=daveabrock.com">recaps all the (free!) JetBrains community webinars</a>.</li><li>Matthew MacDonald <a href="https://medium.com/young-coder/net-has-a-third-party-software-problem-45d24cdc30c9?ref=daveabrock.com">writes about .NET’s third-party software problem</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/blog/2020/12/15/blog/posts/net-foundation-november-december-2020-update?ref=daveabrock.com">provides a November/December 2020 update</a>.</li><li>Telerik <a href="https://www.telerik.com/blogs/the-state-of-dotnet-qa-compilation?ref=daveabrock.com">pulled together a Q&amp;A from a recent .NET 5 webinar</a>.</li></ul><h2 id="-the-net-platform">🥅 The .NET platform</h2><ul><li>Josef Ottosson <a href="https://josef.codes/efficient-file-uploads-with-dotnet/?ref=daveabrock.com">writes about efficient file uploads with .NET</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/how-to-add-user-agent-header-to-httpclient-in-net/?ref=daveabrock.com">adds the User-Agent header to HttpClient</a>.</li><li>Immo Landwerth <a href="https://www.codemag.com/article/2010022?ref=daveabrock.com">writes about transitioning from .NET Standard to .NET 5</a>.</li></ul><h2 id="-web-development">🌎 Web development</h2><ul><li>Sam Walpole <a href="https://hackernoon.com/how-to-optimize-background-tasks-using-hangfire-and-aspnet-core-5j2331ax?source=rss">optimizes background tasks using Hangfire and ASP.NET Core</a>.</li><li>Ed Charbeneau <a href="https://www.telerik.com/blogs/10-blazor-features-you-probably-didnt-know?ref=daveabrock.com">writes about 10 Blazor features you might not know about</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery?ref=daveabrock.com">builds a responsive image gallery in Blazor</a>, and <a href="https://daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm?ref=daveabrock.com">prerenders a Blazor Web Assembly application</a>.</li><li>Sean Franklin <a href="https://www.c-sharpcorner.com/article/blazor-server-how-to-use-local-browser-storage/?ref=daveabrock.com">uses Blazor Server to store encrypted session data in the browser</a>.</li><li>Wael Kdouh <a href="https://medium.com/@waelkdouh/microfrontends-with-blazor-webassembly-b25e4ba3f325?ref=daveabrock.com">writes about microfrontends with Blazor Web Assembly</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/interacting-with-javascript-objects-using-the-new-ijsobjectreference-in-blazor?ref=daveabrock.com">interacts with JavaScript objects using the new IJsObjectReference in Blazor</a>, <a href="https://swimburger.net/blog/dotnet/how-to-deploy-blazor-webassembly-to-firebase-hosting?ref=daveabrock.com">deploys Blazor Web Assembly to Firebase Hosting</a>, and <a href="https://swimburger.net/blog/dotnet/fix-blazor-webassembly-pwa-integrity-checks?ref=daveabrock.com">fixes Blazor Web Assembly PWA integrity checks</a>.</li><li>David Grace <a href="https://www.telerik.com/blogs/client-side-ui-events-and-other-common-queries-blazor?ref=daveabrock.com">writes about client-side UI events and other common queries in Blazor</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/2-step-verification-with-angular-and-aspnet-identity/?ref=daveabrock.com">writes about 2-step verification with Angular and ASP.NET Core Identity</a>.</li><li>Mitchel Sellers <a href="https://www.mitchelsellers.com/blog/article/real-world-localization-implementation-asp-net-core-5?ref=daveabrock.com">writes about real world localization with ASP.NET Core 5</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>David Pine <a href="https://devblogs.microsoft.com/dotnet/localize-net-applications-with-machine-translation?ref=daveabrock.com">writes a GitHub Action to perform machine translation with Azure Cognitive Services</a>.</li><li>Jeffrey Richter <a href="https://devblogs.microsoft.com/azure-sdk/architecture?ref=daveabrock.com">walks us through the Azure SDK architecture</a>.</li><li>David Ellis <a href="https://azure.microsoft.com/blog/5-ways-to-save-costs-by-running-net-apps-on-azure?ref=daveabrock.com">offers tips on how to save when running .NET on Azure</a>.</li><li>Tim Heuer <a href="https://timheuer.com/blog/use-github-actions-for-bulk-resolve-issues/?ref=daveabrock.com">uses GitHub Actions for bulk resolving</a>.</li><li>Damian Brady <a href="https://devblogs.microsoft.com/devops/using-azure-machine-learning-from-github-actions?ref=daveabrock.com">uses GitHub Actions for Azure Machine Learning</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2020/12/19/using-managed-identity-with-azure-keyvault?ref=daveabrock.com">uses Managed Identity with Azure Key Vault</a>, and <a href="https://www.pmichaels.net/2020/12/26/receiving-messages-in-azure-service-bus?ref=daveabrock.com">receives messages through the Azure Service Bus</a>.</li><li>Samson Amaugo <a href="https://auth0.com/blog/making-crud-api-with-azure-functions/?ref=daveabrock.com">makes a CRUD API using Azure Functions and Azure Cosmos DB</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/csharp-9-covariant-return-types?ref=daveabrock.com">writes about C# 9 covariant return types</a>, and <a href="https://khalidabuhakmeh.com/avoid-csharp-9-record-gotchas?ref=daveabrock.com">warns about C# 9 record gotchas</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/the-proper-usages-of-exceptions-in-c/?ref=daveabrock.com">writes about the proper usages of exceptions in C#</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/playing-with-csharp-9-top-level-programs-records-and-elasticsearch-dotnet?ref=daveabrock.com">plays with C# 9 top-level programs, records, and Elasticsearch.NET</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2020/12/nullable-reference-types-csharp-strictnullchecks.html?ref=daveabrock.com">writes about nullable reference types in C#</a>.</li><li>Eric Potter <a href="http://humbletoolsmith.com/2020/12/18/upgrading-old-csharp-to-csharp-9-init-only-setters/?ref=daveabrock.com">writes about init-only setters in C# 9</a>.</li><li>Thomas Levesque <a href="https://thomaslevesque.com/2020/12/23/csharp-9-records-as-strongly-typed-ids-part-4-entity-framework-core-integration/?ref=daveabrock.com">shows off how you can use C# 9 records with EF Core</a>.</li><li>Mark Heath <a href="https://markheath.net/post/coord-performance-versus-readability?ref=daveabrock.com">weighs performance and readability when storing coordinates in C#</a>.</li><li>Reed Copsey <a href="http://reedcopsey.com/2020/12/17/f-basics-result?ref=daveabrock.com">binds with F#</a>.</li><li>Riccardo Terrell <a href="http://www.rickyterrell.com/?p=214&ref=daveabrock.com">builds a recommendation engine with ML.NET and F#</a>.</li><li>Jamie Dixon <a href="https://jamessdixon.com/2020/12/26/looking-at-sars-cov-2-genome-with-f/?ref=daveabrock.com">looks at the SARS-CoV-2 genome with F#</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Mark Heath <a href="https://markheath.net/post/sql-container-with-tye?ref=daveabrock.com">configures SQL Server dependencies in ASP.NET microservices with Project Tye</a>.</li><li>Sam Walpole <a href="https://hackernoon.com/the-top-4-nuget-packages-according-to-this-software-developer-r53c3150?source=rss">shows off Automapper, Mediatr, Swagger, and Fluent Validation</a>.</li><li>Charles Flatt <a href="https://www.softwaremeadows.com/posts/nuget_5_7+_ignores_nuspec_replacement_tokens_-_and_other_weird_behavio/?ref=daveabrock.com">writes about interesting behaviors with NuGet 5.7+</a>.</li><li>John Reilly <a href="https://blog.johnnyreilly.com/2020/12/prettier-your-csharp-with-dotnet-format-and-lint-staged.html?ref=daveabrock.com">prettifies C# with dotnet-format and lint-staged</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/scott-hanselmans-2021-ultimate-developer-and-power-users-tool-list-for-windows?ref=daveabrock.com">provides a 2021 update for his Developer and Power Users Tool List for Windows</a>.</li></ul><h2 id="-security">🔐 Security</h2><ul><li>Giorgi Dalakishvili <a href="https://developer.okta.com/blog/2020/12/18/how-to-use-webauthn-csharp-dotnet?ref=daveabrock.com">uses WebAuthn with C#</a>.</li><li>Gergely Sinka <a href="https://developer.okta.com/blog/2020/12/15/okta-linux-dotnet-server-support?ref=daveabrock.com">supports .NET Core SameSite + OAuth apps on Linux</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/using-csharp-extension-methods-for-auth0-authentication/?ref=daveabrock.com">uses C# extension methods for Auth0 authentication</a>.</li></ul><h2 id="-design-architecture-and-testing">👍 Design, architecture, and testing</h2><ul><li>Derek Comartin <a href="https://codeopinion.com/scaling-a-monolith-horizontally?ref=daveabrock.com">scales a monolith horizontally</a>.</li><li>Steve Smith <a href="https://ardalis.com/data-deficient-messages/?ref=daveabrock.com">writes about data-deficient messages</a>.</li><li>Pavel Krymets <a href="https://devblogs.microsoft.com/azure-sdk/unit-testing-and-mocking/?ref=daveabrock.com">unit tests and mocks with the Azure .NET SDK</a>.</li><li>Sean Killeen <a href="https://seankilleen.com/2020/12/utilizing-the-builder-pattern-and-bogus-for-better-supporting-test-objects/?ref=daveabrock.com">utilizes the Bogus library for better mocks</a>.</li><li>Kevin Avignon <a href="https://kevinavignon.com/2020/12/23/guidelines-to-improve-your-software-design-skills-with-net-part-i/?ref=daveabrock.com">writes about guidelines to improve your .NET software design skills</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Charlin Agramonte <a href="https://xamgirl.com/understanding-multi-binding-in-xamarin-forms/?ref=daveabrock.com">writes about multi-binding in Xamarin Forms</a>.</li><li>James Montemagno <a href="https://montemagno.com/introducing-my-cadence-for-ios-a-simple-cadence-sensor-display/?ref=daveabrock.com">introduces a cadence sensor display for iOS</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/how-to-debug-on-real-android-device-using-xamarin-visual-studio?ref=daveabrock.com">debugs on a real Android device using Xamarin for Visual Studio</a> and also <a href="https://askxammy.com/replicating-christmas-shopping-ui-in-xamarin-forms/?ref=daveabrock.com">replicates a Christmas shopping UI</a>.</li><li>Suthahar <a href="https://www.msdevbuild.com/2020/01/deploy-xamarinios-app-to-ios-device.html?ref=daveabrock.com">deploys Xamarin.iOS app to iOS devices without an Apple Developer account</a> and also <a href="https://www.msdevbuild.com/2020/02/microsoft-ai-xamarin-emotion-recognition-Cognitive-Services.html?ref=daveabrock.com">works with emotion recognition in Xamarin</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1718&ref=daveabrock.com">builds a flight simulator in C# with Laura Laban</a>, and <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1719&ref=daveabrock.com">talks to Scott Hunter about .NET 5</a>.</li><li>The 6-Figure Developer Podcast <a href="https://6figuredev.com/podcast/episode-175-dave-glick-statiq-sites-and-open-source/?ref=daveabrock.com">talks to Dave Glick about Statiq and open source</a>, and <a href="https://6figuredev.com/podcast/episode-176-rest-apis-with-irina-scurtu/?ref=daveabrock.com">talks about REST with Irina Scurtu</a>.</li><li>The Azure DevOps Podcast <a href="http://azuredevopspodcast.clear-measure.com/maddy-leger-on-xamarin-in-a-net-5-world-episode-120?ref=daveabrock.com">talks to Maddy Leger about Xamarin in a .NET 5 world</a>, and <a href="http://azuredevopspodcast.clear-measure.com/kendra-havens-on-codespaces-episode-121?ref=daveabrock.com">talks with Kendra Havens about Codespaces</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>Gerald Versluis <a href="https://www.youtube.com/watch?v=D1O_xkNgBXU&ref=daveabrock.com">accesses battery and energy saver info with Xamarin.Essentials</a>.</li><li>The Loosely Coupled Show <a href="https://www.youtube.com/watch?v=6XbBJ6xF-uY&ref=daveabrock.com">talks with Fran Méndez about AsyncAPI</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2020/12/28/EdCharbeneauOnBlazorTesting.aspx?ref=daveabrock.com">David Giard talks to Ed Charbeneau about Blazor testing</a>.</li><li>David Ortinau <a href="https://www.youtube.com/watch?v=gXLRIy1_284&ref=daveabrock.com">validates navigation in Xamarin.Forms</a>, and also <a href="https://www.youtube.com/watch?v=VZxV5lAzDZ0&ref=daveabrock.com">adds a header to the flyout menu in Xamarin</a>.</li><li>Jeremy Likness and Arthur Vickers give a tour of EF Core 5 in <a href="https://www.youtube.com/watch?v=p0UJdoBj-Lc&ref=daveabrock.com">two</a> <a href="https://www.youtube.com/watch?v=b2klBzcALJc&ref=daveabrock.com">videos</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ More with Gruut: Use the Microsoft Bot Framework to analyze emotion with the Azure Face API ]]></title>
        <description><![CDATA[ In this post, we use the Azure Face API to send Gruut attachments. ]]></description>
        <link>https://www.daveabrock.com/2021/01/05/azure-bot-service-image-emotion-api/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe80</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Mon, 04 Jan 2021 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1557342960-7ea3df1d8630?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDl8fGdyb290fGVufDB8fHx8MTYxOTgzMzMzMQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Last summer—it was 2020, I think it was summer—I <a href="https://daveabrock.com/2020/07/28/azure-bot-service-cognitive-services?ref=daveabrock.com">published a post</a> that showed off how to use Azure text sentiment analysis with the Microsoft Bot Framework. I used it to build on <a href="https://twitter.com/shahedC?ref=daveabrock.com">Shahed Chowdhuri</a>’s <a href="https://github.com/shahedc/GruutChatbot?ref=daveabrock.com">GruutChatbot project</a>. The gist was that Gruut would respond with <em>I am Gruut</em> differently based on the conveyed emotion of the text that a user enters. (As before, the project doesn’t have a legal team so we’re using the <em>Gruut</em> naming to avoid any issues from the Smisney Smorporation.)</p><p>Here’s a thought: since the Bot Framework allows users to send attachments, what if we send him a picture? How would Gruut react to sending images of a happy-seeming person, or an upset-seeming person? We can do this with the <a href="https://azure.microsoft.com/services/cognitive-services/face/?ref=daveabrock.com">Azure Face API</a>, which <a href="https://azure.microsoft.com/services/cognitive-services/face/?ref=daveabrock.com#demo">allows us to detect</a> <em>perceived</em> emotions from faces in images. That’s what we’ll do in this post.</p><p><strong>Note</strong>: While we’re using this service innocently, face detection is a serious topic. Make sure you understand what you are doing, and how the data is used. A good first step is <a href="https://azure.microsoft.com/support/legal/cognitive-services-compliance-and-privacy/?ref=daveabrock.com">to check out the Azure Cognitive Services privacy policy</a>. For this post, we’ll be using stock images.</p><h2 id="before-you-start">Before you start</h2><p>In this post, we won’t walk through installing the Bot Framework SDK and Emulator, creating the bot project, and so on—that was covered in the <a href="https://daveabrock.com/2020/07/28/azure-bot-service-cognitive-services?ref=daveabrock.com">first post on the topic</a>. Check out that post if you need to get acclimated.</p><p>We’ll need to <a href="https://portal.azure.com/?ref=daveabrock.com#create/Microsoft.CognitiveServicesFace">create a Face resource</a> in Azure (yes, that’s what it’s called). Once you create that, grab the <code>Endpoint</code> (from the resource in the Azure Portal) and also a key from the <code>Keys and Endpoint</code> section. You can then throw those into Azure Key Vault with the other values (<a href="https://daveabrock.com/2020/07/28/azure-bot-service-cognitive-services?ref=daveabrock.com#second-pass-working-with-credentials-safely">check out the previous post</a> for those instructions).</p><h2 id="process-the-attachment">Process the attachment</h2><p>First, we need to process the attachment. This involves getting the location from the chat context, and downloading the image to a temporary path. Then, we’ll be ready to pass it to the Cognitive Services API. In our renamed <code>GruutBot</code> class, we now need to conditionally work with attachments.</p><p>Here’s how it looks. We’ll dig deeper after reviewing the code.</p><pre><code class="language-csharp">protected override async Task OnMessageActivityAsync(
            ITurnContext&lt;IMessageActivity&gt; turnContext,
            CancellationToken cancellationToken)
{
    string replyText;

    if (turnContext.Activity.Attachments is not null)
    {
      // get url from context, then download to pass along to the service
      var fileUrl = turnContext.Activity.Attachments[0].ContentUrl;
      var localFileName = Path.Combine(Path.GetTempPath(),
              turnContext.Activity.Attachments[0].Name);

      using var webClient = new WebClient();
      webClient.DownloadFile(fileUrl, localFileName);

      replyText = await _imageService.GetGruutResponse(localFileName);
    }
    else
    {
      replyText = await _textService.GetGruutResponse(turnContext.Activity.Text, cancellationToken);
    }

    await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
}
</code></pre><p>Let’s focus on what happens when we receive the attachment.</p><pre><code class="language-csharp">if (turnContext.Activity.Attachments is not null)
{
    // get url from context, then download to pass along to the service
    var fileUrl = turnContext.Activity.Attachments[0].ContentUrl;
    var localFileName = Path.Combine(Path.GetTempPath(),
    turnContext.Activity.Attachments[0].Name);

    using var webClient = new WebClient();
    webClient.DownloadFile(fileUrl, localFileName);

    replyText = await _imageService.GetGruutResponse(localFileName);
}
</code></pre><p>For now, let’s (blindly) assume we only have one attachment, and the attachment is an image. From the <code>turnContext</code> we can retrieve information about the sent message. In our case, we want the <code>ContentUrl</code> of the attachment. We’ll then store it in a temporary path, with the context’s <code>Name</code>. Then, <a href="https://docs.microsoft.com/dotnet/api/system.net.webclient?view=net-5.0&ref=daveabrock.com">using the <code>WebClient</code> API</a>, we can download the file to the local temp directory. With a path set, we can now inspect our <code>GetGruutResponse</code> method in a new image service, which takes a path to where the image resides.</p><h2 id="write-a-new-imageanalysisservice">Write a new ImageAnalysisService</h2><p>Because we’re now using text and analysis SDKs in this app, we should split them out into different services. Let’s begin with a new <code>ImageAnalysisService</code>.</p><p>To kick off a new <code>ImageAnalysisService.cs</code> file, we’ll read in the settings using the <a href="https://docs.microsoft.com/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0&ref=daveabrock.com">ASP.NET Core Options pattern</a> with <code>ImageApiOptions</code>. These align with what I’ve got stored in the Azure Key Vault.</p><pre><code class="language-csharp">namespace GruutChatbot.Services.Options
{
    public class ImageApiOptions
    {
        public string FaceEndpoint { get; set; }
        public string FaceCredential { get; set; }
    }
}
</code></pre><p>Then, after bringing in the <code>Microsoft.Azure.CognitiveServices.Vision.Face</code> NuGet library, we can use constructor dependency injection to “activate” our services. Here’s the beginning of the class:</p><pre><code class="language-csharp">namespace GruutChatbot.Services
{
    public class ImageAnalysisService
    {
        readonly ImageApiOptions _imageApiSettings;
        readonly ILogger&lt;ImageAnalysisService&gt; _logger;
        readonly FaceClient _imageClient;

        public ImageAnalysisService(
            IOptions&lt;ImageApiOptions&gt; options,
            ILogger&lt;ImageAnalysisService&gt; logger)
        {
            _imageApiSettings = options.Value ?? throw new
                ArgumentNullException(nameof(options),
                "Image API options are required.");
            _logger = logger;
            _imageClient = new FaceClient(
                new ApiKeyServiceClientCredentials(
                    _imageApiSettings.FaceCredential))
            {
                Endpoint = _imageApiSettings.FaceEndpoint
            };
        }
}
</code></pre><p>Now, we’ll write a <code>GetGruutResponse</code> method that takes the file path to our downloaded attachment. Here’s how the method looks (we’ll dig in after):</p><pre><code class="language-csharp">public async Task&lt;string&gt; GetGruutResponse(string filePath)
{
  try
  {
    var faceAttributes = new List&lt;FaceAttributeType?&gt;
       { FaceAttributeType.Emotion};

    using var imageStream = File.OpenRead(filePath);

    var result = await _imageClient.Face.DetectWithStreamAsync(
              imageStream, true, false, faceAttributes);

    return GetReplyText(GetHeaviestEmotion(result));
  }
  catch (Exception ex)
  {
    _logger.LogError(ex.Message, ex);
  }
  return string.Empty;
}
</code></pre><p>First, we need to <a href="https://docs.microsoft.com/dotnet/api/microsoft.azure.cognitiveservices.vision.face.models.faceattributetype?view=azure-dotnet&ref=daveabrock.com">pass in a <code>List&lt;FaceAttributeType?&gt;</code></a>, which tells the SDK which face attributes you want back. There’s a ton of options, like <code>FacialHair</code>, <code>Gender</code>, <code>Hair</code>, <code>Blur</code>, and so on—we just need <code>Emotion</code>.</p><pre><code>var faceAttributes = new List&lt;FaceAttributeType?&gt;
                    { FaceAttributeType.Emotion};
</code></pre><p>Then, we’ll open up a <code>FileStream</code> for the file in question.</p><pre><code class="language-csharp">using var imageStream = File.OpenRead(filePath);
</code></pre><p>To make the Cognitive Services call, we can call the <code>DetectWithStreamAsync</code> method. The <code>true</code> switch is to return a <code>faceId</code>, and the <code>false</code> is for not returning landmarks.</p><pre><code class="language-csharp">var result = await _imageClient.Face.DetectWithStreamAsync(
                    imageStream, true, false, faceAttributes);
</code></pre><p>When we call this, we’re going to get a list of all different emotions and their values, from 0 to 1. For us, we’d like to pick the emotion that carries the most weight. To do that, I wrote a <code>GetHeaviestEmotion</code> method. This is a common use case, as the SDK has a <code>ToRankedList</code> extension method <a href="https://docs.microsoft.com/dotnet/api/microsoft.azure.cognitiveservices.vision.face.emotionextensions.torankedlist?view=azure-dotnet&ref=daveabrock.com">that suits my needs</a>.</p><pre><code>private string GetHeaviestEmotion(IList&lt;DetectedFace&gt; imageList) =&gt;
            imageList.FirstOrDefault().FaceAttributes.Emotion.
                ToRankedList().FirstOrDefault().Key;
</code></pre><p>Now, all that’s left is to figure out what to send to Gruut. I created a <code>GruutMoods</code> class that just has some <code>static readonly</code> strings for ease of use:</p><pre><code class="language-csharp">namespace GruutChatbot.Services
{
    public static class GruutMoods
    {
        public readonly static string PositiveGruut = "I am Gruut.";
        public readonly static string NeutralGruut = "I am Gruut?";
        public readonly static string NegativeGruut = "I AM GRUUUUUTTT!!";
        public readonly static string FailedGruut = "I.AM.GRUUUUUT";
    }
}
</code></pre><p>Now, we can use a switch expression to determine what to send back:</p><p><strong>Note</strong>: I classified the perceived emotions based on trial-and-error using a few images. Your mileage may vary.</p><pre><code>private static string GetReplyText(string emotion) =&gt; emotion switch
{
  "Happiness" or "Surprise" =&gt; GruutMoods.PositiveGruut,
  "Anger" or "Contempt" or "Disgust" or "Sadness" =&gt;
           GruutMoods.NegativeGruut,
  "Neutral" or "Fear" =&gt; GruutMoods.NeutralGruut,
  _ =&gt; GruutMoods.FailedGruut
};
</code></pre><p>So now, in <code>GetGruutResponse</code> this is what we’ll return:</p><pre><code class="language-csharp">return GetReplyText(GetHeaviestEmotion(result));
</code></pre><p>Again, here’s all of <code>GetGruutResponse</code> for your reference:</p><pre><code class="language-csharp">public async Task&lt;string&gt; GetGruutResponse(string filePath)
{
    try
    {
      var faceAttributes = new List&lt;FaceAttributeType?&gt;
        { FaceAttributeType.Emotion};

      using var imageStream = File.OpenRead(filePath);

      var result = await _imageClient.Face.DetectWithStreamAsync(
                  imageStream, true, false, faceAttributes);

      return GetReplyText(GetHeaviestEmotion(result));
    }
    catch (Exception ex)
    {
      _logger.LogError(ex.Message, ex);
    }

    return string.Empty;
}
</code></pre><p>And finally, the entirety of <code>ImageAnalysisService</code>:</p><pre><code class="language-csharp">using GruutChatbot.Services.Options;
using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace GruutChatbot.Services
{
    public class ImageAnalysisService
    {
        readonly ImageApiOptions _imageApiSettings;
        readonly ILogger&lt;ImageAnalysisService&gt; _logger;
        readonly FaceClient _imageClient;

        public ImageAnalysisService(
            IOptions&lt;ImageApiOptions&gt; options,
            ILogger&lt;ImageAnalysisService&gt; logger)
        {
            _imageApiSettings = options.Value ?? throw new
                ArgumentNullException(nameof(options),
                "Image API options are required.");
            _logger = logger;
            _imageClient = new FaceClient(
                new ApiKeyServiceClientCredentials(
                    _imageApiSettings.FaceCredential))
            {
                Endpoint = _imageApiSettings.FaceEndpoint
            };
        }

        public async Task&lt;string&gt; GetGruutResponse(string filePath)
        {
            try
            {
                var faceAttributes = new List&lt;FaceAttributeType?&gt;
                    { FaceAttributeType.Emotion};

                using var imageStream = File.OpenRead(filePath);

                var result = await _imageClient.Face.DetectWithStreamAsync(
                    imageStream, true, false, faceAttributes);

                return GetReplyText(GetHeaviestEmotion(result));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, ex);

            }

            return string.Empty;
        }

        private string GetHeaviestEmotion(IList&lt;DetectedFace&gt; imageList) =&gt;
            imageList.FirstOrDefault().FaceAttributes.Emotion.
                ToRankedList().FirstOrDefault().Key;

        private static string GetReplyText(string emotion) =&gt; emotion switch
        {
            "Happiness" or "Surprise" =&gt; GruutMoods.PositiveGruut,
            "Anger" or "Contempt" or "Disgust" or "Sadness" =&gt;
              GruutMoods.NegativeGruut,
            "Neutral" or "Fear" =&gt; GruutMoods.NeutralGruut,
            _ =&gt; GruutMoods.FailedGruut
        };
    }
}
</code></pre><p>Also, if you aren’t aware, you’ll need to add the service to the DI container in <code>Startup.cs</code>:</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    // Create the Bot Framework Adapter with error handling enabled.
    services.AddSingleton&lt;IBotFrameworkHttpAdapter, AdapterWithErrorHandler&gt;();

    // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
    services.AddTransient&lt;IBot, GruutBot&gt;();

    // some stuff removed for brevity

    services.Configure&lt;ImageApiOptions&gt;(Configuration.GetSection(nameof(ImageApiOptions)));
    services.Configure&lt;TextApiOptions&gt;(Configuration.GetSection(nameof(TextApiOptions)));

    services.AddSingleton&lt;ImageAnalysisService&gt;();
    services.AddSingleton&lt;TextAnalysisService&gt;();    
}
</code></pre><h2 id="repeat-with-textanalysisservice">Repeat with TextAnalysisService</h2><p>With this in place, a refactored <code>TextAnalysisService</code> takes the same shape and looks like this:</p><pre><code class="language-csharp">using Azure;
using Azure.AI.TextAnalytics;
using GruutChatbot.Services.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace GruutChatbot.Services
{
    public class TextAnalysisService
    {
        readonly TextApiOptions _textApiOptions;
        readonly ILogger&lt;TextAnalysisService&gt; _logger;
        readonly TextAnalyticsClient _textClient;

        public TextAnalysisService(
            IOptions&lt;TextApiOptions&gt; options,
            ILogger&lt;TextAnalysisService&gt; logger)
        {
            _textApiOptions = options.Value ?? throw new
                ArgumentNullException(nameof(options),
                "Text API options are required.");
            _logger = logger;
            _textClient = new TextAnalyticsClient(
                new Uri(_textApiOptions.CognitiveServicesEndpoint),
                new AzureKeyCredential(_textApiOptions.AzureKeyCredential));
        }

        public async Task&lt;string&gt; GetGruutResponse(string inputText, 
                CancellationToken cancellationToken)
        {
            try
            {
                var result = await _textClient.AnalyzeSentimentAsync(
                    inputText,
                    cancellationToken: cancellationToken);

                return GetReplyText(result.Value.Sentiment);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, ex);

            }

            return string.Empty;
        }

        static string GetReplyText(TextSentiment sentiment) =&gt; sentiment switch
        {
            TextSentiment.Positive =&gt; GruutMoods.PositiveGruut,
            TextSentiment.Negative =&gt; GruutMoods.NegativeGruut,
            TextSentiment.Neutral =&gt; GruutMoods.NeutralGruut,
            _ =&gt; GruutMoods.FailedGruut
        };
    }
}
</code></pre><h2 id="the-final-product">The final product</h2><p>Now, with our SDK calls refactored to services, here’s our full <code>GruutBot</code>:</p><pre><code class="language-csharp">using GruutChatbot.Services;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace GruutChatbot.Bots
{
    public class GruutBot : ActivityHandler
    {
        private readonly TextAnalysisService _textService;
        private readonly ImageAnalysisService _imageService;

        public GruutBot(TextAnalysisService textService, ImageAnalysisService imageService)
        {
            _textService = textService;
            _imageService = imageService;
        }

        protected override async Task OnMessageActivityAsync(
            ITurnContext&lt;IMessageActivity&gt; turnContext,
            CancellationToken cancellationToken)
        {
            string replyText;

            if (turnContext.Activity.Attachments is not null)
            {
                // get url from context, then download to pass along to the service
                var fileUrl = turnContext.Activity.Attachments[0].ContentUrl;
                var localFileName = Path.Combine(Path.GetTempPath(),
                    turnContext.Activity.Attachments[0].Name);

                using var webClient = new WebClient();
                webClient.DownloadFile(fileUrl, localFileName);

                replyText = await _imageService.GetGruutResponse(localFileName);
            }
            else
            {
                replyText = await _textService.GetGruutResponse(turnContext.Activity.Text, cancellationToken);
            }

            await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);

        }

        protected override async Task OnMembersAddedAsync(
            IList&lt;ChannelAccount&gt; membersAdded,
            ITurnContext&lt;IConversationUpdateActivity&gt; turnContext,
            CancellationToken cancellationToken)
        {
            // welcome new users
        }
    }
}
</code></pre><h2 id="the-bot-in-action">The bot in action</h2><p>Now, let’s see how the bot looks when we send Gruut text and images.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/gruut-images.png" class="kg-image" alt="GruutBot in action" loading="lazy" width="1095" height="1577" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/gruut-images.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/gruut-images.png 1000w, https://www.daveabrock.com/content/images/2021/05/gruut-images.png 1095w" sizes="(min-width: 720px) 720px"></figure><h2 id="wrap-up">Wrap up</h2><p>In this post, we showed how to use Azure Cognitive Services face emotion detection with the Microsoft Bot Framework. We processed and downloaded attachments, passed them to a new <code>ImageAnalysisService</code>, and called the Face API to detect perceived emotion. Then, we wrote logic to send a message back to Gruut. Finally, we showed a refactoring of the existing text analysis to a new <code>TextAnalysisService</code>, which allows us to manage calls to different APIs seamlessly.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Prerender a Blazor Web Assembly application ]]></title>
        <description><![CDATA[ In this post, we speed up initial load time by prerendering our Blazor Web Assembly application. ]]></description>
        <link>https://www.daveabrock.com/2020/12/27/blast-off-blazor-prerender-wasm/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 26 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1451187580459-43490279c0fa?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRlY2h8ZW58MHx8fHwxNjE5ODMzNDc1&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>, <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolated our service dependencies</a>, worked on <a href="https://daveabrock.com/2020/12/13/blast-off-blazor-cosmos?ref=daveabrock.com">hosting our images over Azure Blob Storage and Cosmos DB</a>, and <a href="https://daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery?ref=daveabrock.com">built a responsive image gallery</a>.</p><p>I did some housekeeping with the code that I won’t mention here, such as renaming projects. Check out <a href="https://github.com/daveabrock/NASAImageOfDay?ref=daveabrock.com">the GitHub repo</a> for the latest.</p><p>Now, we need to discuss how to mitigate the biggest drawback of using Blazor Web Assembly: the initial load time. While the Web Assembly solution allows us to enjoy a serverless deployment scenario and fast interactions, the initial download can take awhile. Users need to sit around while the browser downloads the .NET runtime and all your project’s DLLs.</p><p>While the ASP.NET Core team has made a lot of progress in improving the .NET IL linker and making framework libraries more linkable, the initial startup time of Blazor Web Assembly apps is still quite noticeable. In my case, an initial, uncached download takes <em>7 seconds</em>. With prerendering, I was able to cut this down considerably. That is the focus of this post.</p><p>With ahead-of-time (AoT) compilation <a href="https://github.com/dotnet/aspnetcore/issues/5466?ref=daveabrock.com">coming with .NET 6</a>, you might be inclined to treat it as a fix to this problem. AoT will not help decrease the app download size because Web Assembly uses an Intermediate Language (IL) interpreter and isn’t a JIT-based runtime. In terms of performance, AoT can speed up runtime performance but will mean an even <em>larger</em> download size. See <a href="https://github.com/dotnet/aspnetcore/issues/5466?ref=daveabrock.com#issuecomment-639890420">Dan Roth’s comment for details</a>.</p><p>This post covers the following content.</p><ul><li><a href="#what-is-prerendering">What is prerendering?</a></li><li><a href="#configure-the-blastoffserver-project">Configure the <code>BlastOff.Server</code> project</a></li><li><a href="#share-the-service-layer">Share the service layer</a></li><li><a href="#check-our-progress">Check our progress</a></li><li><a href="#wrap-up">Wrap up</a></li><li><a href="#references">References</a></li></ul><p>This post builds off the wonderful content from <a href="https://chrissainty.com/prerendering-a-client-side-blazor-application/?ref=daveabrock.com">Chris Sainty</a>, <a href="https://jonhilton.net/blazor-wasm-prerendering/?ref=daveabrock.com">Jon Hilton</a>, and the <a href="https://docs.microsoft.com/aspnet/core/blazor/components/prerendering-and-integration?view=aspnetcore-5.0&pivots=webassembly&ref=daveabrock.com">ASP.NET Core documentation</a>.</p><h2 id="what-is-prerendering">What is prerendering?</h2><p>Without prerendering, your Blazor Web Assembly app parses the <code>index.html</code> file it receives, then fetches all your dependencies. Then, it’ll load and launch your application—leaving you with a less-than-ideal UX as users are sitting and waiting. With prerendering, the initial load occurs on the server with the download occurring in the background. By the time the page quickly loads and the download completes, your users are ready to interact with your site—with a big Blazor Web Assembly drawback out of the way.</p><p>When we say <em>prerendering</em>, we really mean <em>prerendering components</em>. We do this by integrating our app using Razor Pages. The cost here: you’re kissing goodbye to a simple static file deployment in favor of faster startup times.</p><p>This is not simply converting your app to <a href="https://docs.microsoft.com/aspnet/core/blazor/hosting-models?view=aspnetcore-5.0&ref=daveabrock.com#blazor-server">a Blazor Server solution</a>. While Blazor Server executes your application from a server-side ASP.NET Core app, this is compiling your code and serving static assets from a server project. You’re still running your app in a browser as you were before.</p><p>To get started, we need to create and configure a <code>Server</code> project.</p><h2 id="configure-the-blastoff-server-project">Configure the BlastOff.Server project</h2><p>To get started, you’ll need to create a new <code>BlastOff.Server</code> project and add it to the solution. The easiest and simplest way is using the <code>dotnet</code> CLI.</p><p>To create a new project, I executed the following from the root of the project (where the solution file is):</p><pre><code>dotnet new web -o BlastOff.Server
</code></pre><p>Then, I added it to my existing solution:</p><pre><code>dotnet sln add BlastOff.Server/BlastOff.Server.csproj
</code></pre><p>In the new <code>BlastOff.Server</code> project, I headed over to <code>Startup.cs</code> and updated the <code>Configure</code> method to the following:</p><pre><code class="language-csharp">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    public void Configure(IApplicationBuilder app)
    {
        // some code removed for brevity

        app.UseBlazorFrameworkFiles();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseEndpoints(endpoints =&gt;
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
}
</code></pre><p>With the <code>IApplicationBuilder</code> interface, we’ll call <code>UseBlazorFrameworkFiles()</code> that will allow us to serve Blazor Web Assembly files from a specified path. The <code>UseStaticFiles()</code> call enables us to serve static files.</p><p>After enabling routing, we use the endpoint middleware to work with Razor Pages, which is the secret sauce behind this magic. Then, in <code>MapFallbackToPage()</code>, we’re serving a <code>/_Host.cshtml</code> file in the <code>Server</code> project’s <code>Pages</code> directory.</p><p>This <code>_Host.cshtml</code> file will replace our <code>Client</code> project’s <code>index.html</code> file. Therefore, we can copy the contents of our <code>index.html</code> here.</p><p>You’ll notice below that we:</p><ul><li>Set the namespace to <code>BlastOff.Server.Pages</code></li><li>Set a <code>@using</code> directive to the <code>BlastOff.Client</code> project</li><li>Make sure the <code>&lt;link href&gt;</code> references resolve correctly</li><li>Update the <a href="https://docs.microsoft.com/aspnet/core/mvc/views/tag-helpers/built-in/component-tag-helper?view=aspnetcore-5.0&ref=daveabrock.com">Component Tag Helper</a> to include a <code>render-mode</code> of <code>WebAssemblyPrerendered</code>. This option prerenders the component into static HTML and includes a flag for the app to make the component interactive when the browser loads it</li><li>Ensure the Blazor script points to the client script at <code>_framework/blazor.webassembly.js</code></li></ul><p>Here’s the <code>_Host.cshtml</code> file in its entirety:</p><pre><code class="language-html">@page "/"
@namespace BlastOff.Server.Pages
@using BlastOff.Client

&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="utf-8" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;Blast Off With Blazor&lt;/title&gt;
    &lt;base href="~/" /&gt;
    &lt;link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /&gt;
    &lt;link href="css/site.css" rel="stylesheet" /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;app&gt;
        &lt;component type="typeof(App)" render-mode="WebAssemblyPrerendered" /&gt;
    &lt;/app&gt;

    &lt;script src="_framework/blazor.webassembly.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>With this in place, I headed over to the <code>BlastOff.Client</code> project to delete <code>wwwroot/index.html</code> and this line from <code>Program.Main</code>. It felt both nice and weird.</p><pre><code class="language-csharp">builder.RootComponents.Add&lt;App&gt;("#app");
</code></pre><h2 id="share-the-service-layer">Share the service layer</h2><p>With prerendering, we need to think about how our calls to Azure Functions work. Previously, our API calls were from the <code>BlastOff.Client</code> project. With prerendering, it’ll first need to make these calls from the server. As a result, it’ll make better sense to move our service layer out of the <code>BlastOff.Client</code> project and to a new <code>BlastOff.Shared</code> project.</p><p>Here’s our <code>ImageService</code> now (I also moved the <code>Image</code> model here for good measure):</p><pre><code class="language-csharp">using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace BlastOff.Shared
{
    public interface IImageService
    {
        public Task&lt;IEnumerable&lt;Image&gt;&gt; GetImages(int days);
    }

    public class ImageService : IImageService
    {
        readonly IHttpClientFactory _clientFactory;
        readonly ILogger&lt;ImageService&gt; _logger;

        public ImageService(ILogger&lt;ImageService&gt; logger, IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
            _logger = logger;
        }

        public async Task&lt;IEnumerable&lt;Image&gt;&gt; GetImages(int days)
        {
            try
            {
                var client = _clientFactory.CreateClient("imageofday");
                var images = await client.GetFromJsonAsync
                    &lt;IEnumerable&lt;Image&gt;&gt;($"api/image?days={days}");
                return images.OrderByDescending(img =&gt; img.Date);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, ex);
            }

            return default;
        }
    }
}
</code></pre><p>We can thank ourselves for <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolating our service dependency a few posts ago</a>–turning a potential headache to some copying and pasting. The only cleanup in our <code>BlastOff.Client</code> project is to bring in the <code>BlastOff.Shared</code> project to reference our service in <code>Program.cs</code>:</p><pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using BlastOff.Shared;

namespace BlastOff.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.Services.AddHttpClient("imageofday", iod =&gt;
            {
                iod.BaseAddress = new Uri("http://localhost:7071" ?? builder.HostEnvironment.BaseAddress);
            });
            builder.Services.AddScoped&lt;IImageService, ImageService&gt;();

            await builder.Build().RunAsync();
        }
    }
}
</code></pre><p>If we run the app, it loads much quicker. When we browse to <code>/images</code> it loads fast too. But if we hit reload, we’ll see a nasty error because we didn’t register the <code>ImageService</code> in our <code>Server</code> project. In the DI container logic in <code>Startup.ConfigureServices</code>, then, add the <code>HttpClient</code> and <code>ImageService</code> references:</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddHttpClient("imageofday", iod =&gt;
    {
        iod.BaseAddress = new Uri("http://localhost:7071");
    });

    services.AddScoped&lt;IImageService, ImageService&gt;();
}
</code></pre><h2 id="check-our-progress">Check our progress</h2><p>Check out how much better everything looks now. Much better.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/Prerender.gif" class="kg-image" alt="Our slow site" loading="lazy" width="1908" height="1016"></figure><h2 id="wrap-up">Wrap up</h2><p>In this post, we worked through how to prerender our Blazor Web Assembly application. We created a new server project, shared our dependencies in a new project, and understood how prerendering can significantly improve initial load times.</p><h2 id="references">References</h2><ul><li><a href="https://chrissainty.com/prerendering-a-client-side-blazor-application/?ref=daveabrock.com">Prerendering a Client-side Blazor Application</a> (Chris Sainty)</li><li><a href="https://jonhilton.net/blazor-wasm-prerendering/?ref=daveabrock.com">Prerendering your Blazor WASM application with .NET 5</a> (Jon Hilton)</li><li><a href="https://docs.microsoft.com/aspnet/core/blazor/components/prerendering-and-integration?view=aspnetcore-5.0&pivots=webassembly&ref=daveabrock.com">Prerender and integrate ASP.NET Core Razor components</a> (Microsoft Docs)</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #30: 🥂 See ya, 2020 ]]></title>
        <description><![CDATA[ This week, we wrap up 2020 with some news, a look back, and a coding tip. ]]></description>
        <link>https://www.daveabrock.com/2020/12/19/dotnet-stacks-30/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 18 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-15.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter, The .NET Stacks. It was originally sent to subscribers on December 14, 2020. Subscribe at the bottom of this post to get the content right away!</em></p><p>👋 Happy Monday, everyone! This is the very last issue of 2020. Every year, I try to take the last few weeks off to decompress and unplug—considering how 2020 went, this year is no exception.</p><h2 id="-news-and-announcements">📰 News and announcements</h2><p>GitHub Universe 2020 occurred this week, and <a href="https://github.blog/2020-12-08-new-from-universe-2020-dark-mode-github-sponsors-for-companies-and-more/?ref=daveabrock.com">Shanku Niyogi has all the details</a>. (As .NET developers, the gap between .NET and GitHub will continue to narrow as Microsoft will <a href="https://daveabrock.com/2020/08/15/dotnet-stacks-12?ref=daveabrock.com#github-actions-or-azure-devops">pivot to GitHub Actions as its long-term CI/CD solution</a>.)</p><p>The GitHub site itself stole the show. Dark Mode is now supported natively—you can delete your favorite browser extensions that do this for you. Also, the front page is a site to behold. Just hover over a globe to see commits in real-time from across the world:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/gh-globe.png" class="kg-image" alt="The GitHub globe" loading="lazy" width="1113" height="1228" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/gh-globe.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/gh-globe.png 1000w, https://www.daveabrock.com/content/images/2021/05/gh-globe.png 1113w" sizes="(min-width: 720px) 720px"></figure><p>As for actual development features, we now see the ability to auto-merge PRs, discussions, CD support. Also, companies can now invest in OSS with <a href="https://github.com/sponsors?ref=daveabrock.com">the GitHub Sponsors program</a>.</p><p>What does this Sponsors news mean for the .NET OSS ecosystem? That is a complicated question. <a href="https://github.com/dotnet-foundation/ecosystem-growth/blob/main/docs/theme.md?ref=daveabrock.com#grow-the-set-of-trusted-libraries-that-arent-controlled-by-microsoft">.NET PM Immo Landwerth wrote about it</a>:</p><blockquote>Today, we’re usually reactive when it comes to library &amp; framework investments. By the time we know there is a need for a library we routinely research existing options but usually end up rolling our own, because nothing fits the bill as-is and we either don’t have the time or we believe we wouldn’t be able to successfully influence the design of the existing library. This results in a perception where Microsoft “sucks the air” out of the OSS ecosystem because our solutions are usually more promoted and often tightly integrated into the platform, thus rendering existing solutions less attractive. Several maintainers have cited this as a reason that they gave up or avoid building libraries that seem foundational.</blockquote><blockquote>To avoid this, we need to start engaging with owners of existing libraries and work with them to increase their quality … it should become a general practice. We should even consider an ongoing work item to actively investigate widely used libraries and help them raise the quality or tighten their integration into the .NET developer experience.</blockquote><p>Check out the full discussion here:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Since GitHub extended the concept of sponsoring: I&#39;m not convinced that this is the right fix for the .NET ecosystem at large. Thoughts? <a href="https://t.co/8660CXWQpl?ref=daveabrock.com">https://t.co/8660CXWQpl</a> <a href="https://t.co/qKmzNkvKQn?ref=daveabrock.com">pic.twitter.com/qKmzNkvKQn</a></p>&mdash; Immo Landwerth (@terrajobst) <a href="https://twitter.com/terrajobst/status/1337587757086986241?ref_src=twsrc%5Etfw&ref=daveabrock.com">December 12, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><hr><p>Claire Novotny wrote <a href="https://devblogs.microsoft.com/dotnet/improving-debug-time-productivity-with-source-link/?ref=daveabrock.com">two</a> <a href="https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/?ref=daveabrock.com">posts</a> this week about using Source Link with Visual Studio and Visual Studio Code. <a href="https://github.com/dotnet/sourcelink?ref=daveabrock.com">Source Link</a> has been around a few years, but is now getting the full treatment. If you aren’t familiar, it’s “a language and source-control agnostic system for providing first-class source debugging experiences for binaries.” This helps solve issues when you can’t properly debug an external library (or a .NET library).</p><p>Considering most library code is openly available from a GitHub HTTP request, debugging external dependencies is a lot easier these days. If a library has enabled Source Link, you can work with the code as you would with yours: setting breakpoints, checking values, and so on. I can see benefit personally in something like <code>System.Text.Json</code> or <code>Newtonsoft.Json</code>—it’ll be easier to pinpoint any silly serialization issues I may or may not be causing.</p><p>Claire’s first post <a href="https://devblogs.microsoft.com/dotnet/improving-debug-time-productivity-with-source-link/?ref=daveabrock.com">shows off the value of using Source Link</a>, but for this to work a library’s PDB files need to be properly indexed. Her second post shows <a href="https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/?ref=daveabrock.com">how to add Source Link to your projects</a>.</p><hr><p>Speaking of Visual Studio, Jacqueline Widdis <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-9-preview-2/?ref=daveabrock.com">rolls out Visual Studio 2019 v16.9 Preview 2</a>. We’re seeing a few quality-of-life improvements—<code>using</code> directives are automatically inserted when pasting types, and VS automatically adds semicolons when creating objects and invoking methods.</p><p>Speaking of quality-of-life, the Visual Studio team <a href="https://twitter.com/PratikN/status/1336440895692914690?ref=daveabrock.com">is aware</a> of the underwhelming reception to the Git integration updates added with v16.8. They have a <a href="https://t.co/L8b2rSVjMt?amp=1&ref=daveabrock.com">survey out</a> to understand why a lot of folks are turning off the feature. They’re listening, so fill out the survey to have your voice heard.</p><hr><p>Xin Shi <a href="https://devblogs.microsoft.com/dotnet/infer-interprocedural-memory-safety-analysis-for-c?ref=daveabrock.com">discusses Infer#, which brings you interprocedural static analysis capabilities</a> to .NET. It currently helps you detect null dereferences and resource leaks. They’re working on race condition detection and thread safety violations.</p><hr><p>Igor Velikorossov announced <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-windows-forms-runtime-in-net-5-0/?ref=daveabrock.com">what’s new in the Windows Forms runtime for .NET 5</a>. They include a new <code>TaskDialog</code> control, <code>ListView</code> enhancements, upgrades to <code>FileDialog</code>, and performance and accessibility improvements.</p><hr><p>Anthony Chu <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/net-5-support-on-azure-functions/ba-p/1973055?ref=daveabrock.com">announces that .NET 5 support in Azure Functions is now in early preview</a>. For this to happen, .NET 5 functions need to run in an out-of-process language worker separate from the Azure Functions runtime. As a result, a .NET 5 app runs differently than a 3.1 one; you build an executable that imports the .NET 5 language worker as a NuGet package. Check out <a href="https://github.com/Azure/azure-functions-dotnet-worker-preview?ref=daveabrock.com">the repository readme</a> for the full details. The .NET 5 worker will be generally available in early 2021.</p><p>In other Azure news, Richard Park <a href="https://devblogs.microsoft.com/azure-sdk/november-2020-servicebus-ga/?ref=daveabrock.com">announced the new Azure Service Bus client libraries</a>. Following <a href="https://github.com/Azure/azure-sdk/blob/master/README.md?ref=daveabrock.com">the guidelines for new Azure SDKs</a>, it’s a culmination of months of work and the post includes details on how its making working with core Service Bus functionality quite a bit easier.</p><p>Also, the November 2020 release of the Azure SDKs include the Service Bus updates, as well as updates for Form Recognizer, Identity, and Text Analytics.</p><hr><p>Microsoft released a couple new Learn modules: one on <a href="https://docs.microsoft.com/learn/paths/build-community-driven-projects-github/?ref=daveabrock.com">building projects with GitHub</a>, and another with <a href="https://docs.microsoft.com/learn/modules/introduction-to-powershell?ref=daveabrock.com">an introduction to PowerShell</a>.</p><hr><p>Kubernetes 1.20 has been released. The <a href="https://kubernetes.io/blog/2020/12/08/kubernetes-1-20-release-announcement/?ref=daveabrock.com">release notes are very infra-heavy</a>, but one thing to note is the Dockershim deprecation, which <a href="https://daveabrock.com/2020/12/12/dotnet-stacks-29?ref=daveabrock.com#-kubernetes-is-deprecating-docker--what">we talked about last week</a>.</p><hr><p>Okta has <a href="https://developer.okta.com/blog/2020/12/10/introducing-okta-cli?ref=daveabrock.com">released a new CLI</a>. With one <code>okta start</code> command, it looks like it can register you for a new account (if you don’t have one) and work with a sample ASP.NET Core MVC application.</p><h2 id="dev-tip-nested-tuple-deconstruction">Dev tip: nested tuple deconstruction</h2><p>I’m a fan of deconstructing C# objects <a href="https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-tuples?ref=daveabrock.com">using tuples</a>. Did you know you can nest them? Even though it’s been around awhile, I didn’t.</p><p>David Pine shows us how:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Hey C# developers, have you ever used nested tuple deconstruction? Check it out -- when deconstructing one object that supports deconstruction, you can nest construction all the way down. <a href="https://twitter.com/hashtag/csharp?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#csharp</a> <a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://twitter.com/dotnet?ref_src=twsrc%5Etfw&ref=daveabrock.com">@dotnet</a><a href="https://t.co/h5R7tsU8es?ref=daveabrock.com">https://t.co/h5R7tsU8es</a> <a href="https://t.co/5I6mKRka6b?ref=daveabrock.com">pic.twitter.com/5I6mKRka6b</a></p>&mdash; David Pine 🌲 (@davidpine7) <a href="https://twitter.com/davidpine7/status/1337483995207118849?ref_src=twsrc%5Etfw&ref=daveabrock.com">December 11, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="-a-2020-net-stacks-recap">📆 A 2020 .NET Stacks recap</h2><p>It’s been a busy 2020 at <em>The .NET Stacks</em>, even if we’ve only been around since the end of May. What’s happened since then? Let’s recap.</p><p>The first issue <a href="https://daveabrock.com/2020/05/24/dotnet-stacks-1?ref=daveabrock.com">covered Microsoft Build</a>. We <a href="https://daveabrock.com/2020/05/31/dotnet-stacks-2?ref=daveabrock.com">talked about Project Tye and YARP</a>. We discussed <a href="https://daveabrock.com/2020/06/08/dotnet-stacks-3?ref=daveabrock.com">native .NET feature flags and local k8s dev in Visual Studio</a>, <a href="https://daveabrock.com/2020/06/14/dotnet-stacks-4?ref=daveabrock.com">EF Core</a>, <a href="https://daveabrock.com/2020/06/20/dotnet-stacks-5?ref=daveabrock.com">gRPC-Web and C# 9</a>, <a href="https://daveabrock.com/2020/07/05/dotnet-stacks-6?ref=daveabrock.com">Blazor Mobile Bindings</a>, <a href="https://daveabrock.com/2020/07/12/dotnet-stacks-7?ref=daveabrock.com">Azure SDKs and test automation</a>, and how <a href="https://daveabrock.com/2020/07/18/dotnet-stacks-8?ref=daveabrock.com">C# 9 has become more functional</a>. Then, we <a href="https://daveabrock.com/2020/07/25/dotnet-stacks-9?ref=daveabrock.com">discussed Project Coyote and a new Razor editor</a>, <a href="https://daveabrock.com/2020/08/01/dotnet-stacks-10?ref=daveabrock.com">.NET’s approachability</a>, <a href="https://daveabrock.com/2020/08/08/dotnet-stacks-11?ref=daveabrock.com">Newtonsoft’s new rule and using async void</a>, and <a href="https://daveabrock.com/2020/08/15/dotnet-stacks-12?ref=daveabrock.com">what the future of Azure DevOps looks like</a>.</p><p>Then, we covered <a href="https://daveabrock.com/2020/08/22/dotnet-stacks-13?ref=daveabrock.com">.NET 5 Blazor improvements</a>, <a href="https://daveabrock.com/2020/08/29/dotnet-stacks-14?ref=daveabrock.com">NuGet changes and many-to-many in EF Core 5</a>, <a href="https://daveabrock.com/2020/09/05/dotnet-stacks-15?ref=daveabrock.com">C# source generators</a>, <a href="https://daveabrock.com/2020/09/12/dotnet-stacks-16?ref=daveabrock.com">app trimming</a>, <a href="https://daveabrock.com/2020/09/19/dotnet-stacks-17?ref=daveabrock.com">Blazor CSS isolation</a>, the <a href="https://daveabrock.com/2020/09/26/dotnet-stacks-18?ref=daveabrock.com">fate of .NET Standard</a>, and <a href="https://daveabrock.com/2020/10/03/dotnet-stacks-19?ref=daveabrock.com">a Microsoft Ignite recap</a>. We <a href="https://daveabrock.com/2020/10/09/dotnet-stacks-20?ref=daveabrock.com">introduced route-to-code and talked about what’s happening with IdentityServer</a>, <a href="https://daveabrock.com/2020/10/16/dotnet-stacks-21?ref=daveabrock.com">talked about Azure Static Web Apps</a>, <a href="https://daveabrock.com/2020/10/24/dotnet-stacks-22?ref=daveabrock.com">got excited about .NET 5 and the .NET Foundation</a>, and <a href="https://daveabrock.com/2020/10/31/dotnet-stacks-23?ref=daveabrock.com">talked about how .NET 5 support works</a>.</p><p>After that, we <a href="https://daveabrock.com/2020/11/06/dotnet-stacks-24?ref=daveabrock.com">talked about Blazor’s production readiness</a>, <a href="https://daveabrock.com/2020/11/13/dotnet-stacks-25?ref=daveabrock.com">C# 9 records</a>, and <a href="https://daveabrock.com/2020/11/21/dotnet-stacks-26?ref=daveabrock.com">celebrated the official release of .NET 5</a>. We <a href="https://daveabrock.com/2020/11/28/dotnet-stacks-27?ref=daveabrock.com">gave some love to ASP.NET Core 5</a>, talked about the <a href="https://daveabrock.com/2020/12/05/dotnet-stacks-28?ref=daveabrock.com">future of APIs in ASP.NET Core MVC</a>, and <a href="https://daveabrock.com/2020/12/12/dotnet-stacks-29?ref=daveabrock.com">talked about how to switch controllers to route-to-code</a>. And now, we’re here.</p><p>Along the way, we’ve had some wonderful interviews from community leaders. We discussed <a href="https://daveabrock.com/2020/06/13/dev-discussions-isaac-levin?ref=daveabrock.com">the PresenceLight project</a>, <a href="https://daveabrock.com/2020/06/28/dev-discussions-shahed-chowdhuri?ref=daveabrock.com">writing about ASP.NET Core from A-Z</a>, <a href="https://daveabrock.com/2020/07/10/dev-discussions-michael-crump?ref=daveabrock.com">the Azure community</a>, <a href="https://daveabrock.com/2020/07/25/dev-discussions-jeremy-likness-1?ref=daveabrock.com">Entity Framework Core</a>, <a href="https://daveabrock.com/2020/08/15/dev-discussions-scott-addie?ref=daveabrock.com">the Microsoft docs</a>, <a href="https://daveabrock.com/2020/08/29/dev-discussions-luis-quintanilla-1?ref=daveabrock.com">ML.NET</a>, F# and functional programming (from <a href="https://daveabrock.com/2020/09/26/dev-discussions-phillip-carter?ref=daveabrock.com">Microsoft</a> and <a href="https://daveabrock.com/2020/09/19/dev-discussions-isaac-abraham?ref=daveabrock.com">the community</a>), and <a href="https://daveabrock.com/2020/11/01/dev-discussions-james-hickey?ref=daveabrock.com">Coravel</a>. I’ve got interviews coming from LaBrina Loving, Layla Porter, Cecil Phillip, and Steve Sanderson—and welcome any suggestions for future interview subjects.</p><p>I started this newsletter as an experiment to keep my mind sharp during the pandemic, and I’m happy to see how much its grown. I hope you enjoy it, but I’m always open to feedback about how I can make it better for you. I’ll have a survey in early 2021, but if you have anything to share don’t hesitate to reach out.</p><p>See you in 2021! I hope you and your family have a safe and relaxing holiday season.</p><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Chris Woodruff <a href="https://medium.com/rocket-mortgage-technology-blog/implementing-an-effective-architecture-for-asp-net-core-web-api-254f95b8a434?ref=daveabrock.com">implements an effective architecture for ASP.NET Core Web API</a>.</li><li>Martin Ullrich <a href="https://blog.jetbrains.com/dotnet/2020/12/11/tips-tricks-to-improve-your-net-build-setup-with-msbuild-webinar-recording/?ref=daveabrock.com">talks about MSBuild tips and tricks</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/using-action-results-and-content-negotiation-with-route-to-code/?ref=daveabrock.com">uses action results and content negotiation with “route-to-code” APIs</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>The .NET Open Source Days <a href="https://www.eventbrite.com/e/dot-net-open-source-days-virtual-conference-tickets-130081873385?ref=daveabrock.com">is taking place on December 18</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=P4wj8C2C78c&ref=daveabrock.com">talks to our Marvel-ous friend Shahed Chowdhuri</a> about .NET, C#, and Azure.</li><li>For the .NET community standups: ASP.NET <a href="https://www.youtube.com/watch?v=yzLDvQ-bOw8&ref=daveabrock.com">talks about Material.Blazor</a>, Machine Learning discusses <a href="https://www.youtube.com/watch?v=mw66ZzYhP1M&ref=daveabrock.com">submissions for the Virtual ML.NET Hackathon</a>, and Languages &amp; Runtime <a href="https://www.youtube.com/watch?v=cIB4gxqm6EY&ref=daveabrock.com">talk about Infer#</a>.</li></ul><h3 id="-web-development">🌎 Web development</h3><ul><li>Jon Hilton <a href="https://jonhilton.net/blazor-tailwind-dark-mode/?ref=daveabrock.com">writes about dark mode for web apps using Blazor and Tailwind CSS</a>.</li><li>Kevin Griffin <a href="https://consultwithgriff.com/signalr-connection-ids/?ref=daveabrock.com">writes about managing SignalR ConnectionIds</a>.</li><li>John Gathogo <a href="https://devblogs.microsoft.com/odata/passing-odata-query-options-in-the-request-body?ref=daveabrock.com">passes OData query options in the request body</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/user-registration-angular-aspnet-identity/?ref=daveabrock.com">writes about user registration with Angular and ASP.NET Core Identity</a>, and also <a href="https://code-maze.com/custom-validators-and-handling-errors-with-angular-and-asp-net-core-identity/?ref=daveabrock.com">writes about custom validators and handling errors with Angular and ASP.NET Core Identity</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/asp-net-core-web-hosting/how-to-install-an-asp-net-core-in-net-5-app-on-ubuntu-20-04?ref=daveabrock.com">installs ASP.NET Core in a .NET 5 app on Ubuntu 20.04</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-async-file-uploads?ref=daveabrock.com">writes about being cautious with async file uploads in ASP.NET Core</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Chris Noring <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/no-recompile-no-redeploy-managing-features-flags-in-net-core/ba-p/1975999?ref=daveabrock.com">writes about managing .NET feature flags locally and with Azure</a>.</li><li>Tom Kerkhove <a href="https://blog.tomkerkhove.be/2020/12/11/monitoring-azure-service-bus-topic-subscriptions/?ref=daveabrock.com">monitors Azure Service Bus topic subscriptions</a>.</li><li>Gergely Sinka <a href="https://developer.okta.com/blog/2020/12/09/dotnet-cloud-host-publish?ref=daveabrock.com">deploys a .NET Core app to all the clouds</a>.</li><li>Simon Timms <a href="https://oz-code.com/blog/azure/remote-debugging-for-azure-functions-can-be-a-breeze-2?ref=daveabrock.com">writes about remote debugging for Azure Functions</a>.</li><li>Rami Honig <a href="https://oz-code.com/blog/net-c-tips/how-to-mongodb-in-csharp-part-1?ref=daveabrock.com">kicks off a series on using MongoDB with C#</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2020/12/08/using-multiple-apis-in-angular-and-asp-net-core-with-azure-ad-authentication/?ref=daveabrock.com">uses multiple APIs in Angular and ASP.NET Core with Azure AD authentication</a>.</li><li>Abhijit Jana <a href="https://abhijitjana.net/2020/12/07/azure-communication-services/?ref=daveabrock.com">works with Azure Communication Services</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Raymond Chen <a href="https://devblogs.microsoft.com/oldnewthing/20201210-00/?p=104536&ref=daveabrock.com">parses ETL traces with the EventLogReader</a>.</li><li>Julie Lerman <a href="https://www.pluralsight.com/blog/software-development/domain-driven-design-csharp?ref=daveabrock.com">writes about domain-driven design in C#</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2020/12/09/local-function-attributes-c-sharp-9?ref=daveabrock.com">uses local function attributes with C# 9</a>.</li><li>Arthur Casals <a href="https://www.infoq.com/articles/fsharp-5-interview-phillip-carter?ref=daveabrock.com">talks to Phillip Carter about what’s new in F#</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/common-usecases-for-dotnet-reflection?ref=daveabrock.com">writes about common use cases for .NET reflection</a>.</li><li>Thomas Levesque <a href="https://thomaslevesque.com/2020/12/07/csharp-9-records-as-strongly-typed-ids-part-3-json-serialization/?ref=daveabrock.com">continues his series on using C# 9 records as strongly-typed IDs</a>.</li><li>Carmel Eve <a href="https://endjin.com/blog/2020/12/design-patterns-in-csharp-the-proxy-pattern.html?ref=daveabrock.com">writes about the Proxy pattern in C#</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/rethrowing-your-exceptions-wrong-in-dotnet-could-erase-your-stacktrace?ref=daveabrock.com">warns you about rethrowing your exceptions the wrong way</a>.</li><li>Diogo Souza <a href="https://www.red-gate.com/simple-talk/dotnet/net-development/creating-your-first-crud-app-with-suave-and-f/?ref=daveabrock.com">creates a CRUD app with Suave and F#</a>.</li><li>Thomas Ardal <a href="https://blog.elmah.io/predicting-die-hard-fans-with-ml-net-and-csharp/?ref=daveabrock.com">predicts Die Hard fans with ML.NET and C#</a>.</li><li>Tomasz Pęczek <a href="https://www.tpeczek.com/2020/12/cryptography-improvements-in-net-5.html?ref=daveabrock.com">writes about cryptography improvements in .NET 5</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/you-should-be-customizing-your-powershell-prompt-with-psreadline?ref=daveabrock.com">writes about customizing your PowerShell prompt with PSReadLine</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2020/12/09/vs-linux.aspx?ref=daveabrock.com">writes about the community requesting Visual Studio for Linux</a>.</li><li>Lee Briggs <a href="https://www.pulumi.com/blog/embrace-kubernetes-part1/?ref=daveabrock.com">writes about embracing Kubernetes</a>.</li><li>Rachel Appel <a href="https://blog.jetbrains.com/dotnet/2020/12/07/use-c-9-records-and-init-only-properties-in-resharper-and-rider-2020-3/?ref=daveabrock.com">uses C# 9 records and init-only properties in ReSharper and Rider 2020.3</a>.</li><li>Dave Brock <a href="https://daveabrock.com/2020/12/07/make-link-list-with-markdown-and-with-c-sharp?ref=daveabrock.com">automates a Markdown links page (this one!) with Pinboard and C#</a>.</li><li>Xiaoping Wu <a href="https://www.c-sharpcorner.com/article/tutorial-use-entity-framework-core-5-0-in-net-core-3-1-with-mysql-database-by2/?ref=daveabrock.com">uses EF Core 5.0 in .NET Core 3.1 with MySQL</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>James Montemagno <a href="https://montemagno.com/essentials-nugets-for-new-xamarin-projects/?ref=daveabrock.com">writes about 5 essential NuGet packages for new Xamarin projects</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/meet-radpopup-control-xamarin-forms?ref=daveabrock.com">writes about the RadPopUp control</a>.</li><li>Denys Fiediaiev <a href="https://prin53.medium.com/storyboard-xamarin-ios-mvvmcross-e01fed0879f8?ref=daveabrock.com">loads an idiom-specific storyboard in Xamarin.iOS with MvvmCross</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The Xamarin Podcast <a href="https://www.xamarinpodcast.com/83?ref=daveabrock.com">wraps up 2020 and looks ahead to 2021</a>.</li><li>The Complete Developer Podcast <a href="https://completedeveloperpodcast.com/dependencies-in-unit-testing?ref=daveabrock.com">discusses dependencies in unit testing</a>.</li><li>.NET Rocks <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1717&ref=daveabrock.com">talks to Georgia Nelson about building a TwitchBot in Blazor</a>.</li><li>The 6 Figure Developer podcasts <a href="https://6figuredev.com/podcast/episode-173-bunit-a-blazor-testing-library-w-egil-hansen/?ref=daveabrock.com">talks to Egil Hansen about bUnit</a>.</li><li>Serverless Chats <a href="https://www.serverlesschats.com/78/?ref=daveabrock.com">talks about statefulness and serverless with Rodric Rabbah</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Use-an-Existing-NET-Core-Project-Template?ref=daveabrock.com">uses an existing .NET Core project template</a>, and also <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Create-NET-Core-Projects-with-the-Command-Line?ref=daveabrock.com">creates .NET Core projects with the command line</a>.</li><li>Scott Hanselman <a href="https://www.youtube.com/watch?v=lp_CJba4RmU&ref=daveabrock.com">talks about basic home networking</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=Eetj3CmeBQI&ref=daveabrock.com">work through single-file applications in .NET 5</a>.</li><li>The ON.NET Show <a href="https://www.youtube.com/watch?v=UV-VnlcpDhU&ref=daveabrock.com">talks to James Newton-King about gRPC-Web</a>, <a href="https://www.youtube.com/watch?v=zW4INO353Xg&ref=daveabrock.com">introduces microservice patterns</a>, and <a href="https://www.youtube.com/watch?v=1VEMqTw8xSo&ref=daveabrock.com">discusses GraphQL schema design</a>.</li></ul><hr><figure class="kg-card kg-image-card"><img src="https://media.giphy.com/media/j5ncTQKEIROne/source.gif" class="kg-image" alt="Go home" loading="lazy"></figure> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Build a responsive image gallery ]]></title>
        <description><![CDATA[ In this post, we build a responsive image gallery using Blazor and Tailwind CSS. ]]></description>
        <link>https://www.daveabrock.com/2020/12/16/blast-off-blazor-responsive-gallery/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 15 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1507643179773-3e975d7ac515?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGdhbGxlcnl8ZW58MHx8fHwxNjE5ODMzNTQ2&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>, <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolated our service dependencies</a>, and worked on <a href="https://daveabrock.com/2020/12/13/blast-off-blazor-cosmos?ref=daveabrock.com">hosting our images over Azure Blob Storage and Cosmos DB</a>.</p><p>Now, we’re going to query Cosmos DB, fetch our images, and display them in a responsive image gallery. We’ll learn how to reuse components and pass parameters to them.</p><p>After we work on this, we’ll enhance the gallery in future posts, with:</p><ul><li>Enabling the “infinite scrolling” feature with Blazor virtualization</li><li>Filtering and querying images</li><li>Creating a dialog to see a larger image and other details</li></ul><p>This post contains the following content.</p><ul><li><a href="#a-quick-primer">A quick primer</a></li><li><a href="#customize-the-service-layer">Customize the service layer</a></li><li><a href="#update-images-component-to-list-our-image-collection">Update <code>Images</code> component to list our image collection</a></li><li><a href="#create-a-reusable-imagecard-component">Create a reusable <code>ImageCard</code> component</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="a-quick-primer">A quick primer</h2><p>If you haven’t been with me for the whole series, we’re building a Blazor Web Assembly app <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">hosted with Azure Static Web Apps</a> at <em><a href="https://blastoffwithblazor.com/?ref=daveabrock.com">blastoffwithblazor.com</a></em>. I’ve copied images from the NASA APOD API (all 25 years!) <a href="https://daveabrock.com/2020/11/25/assets/img-azure-blobs-cosmos?ref=daveabrock.com">to Azure Blob Storage</a>, and are storing the image metadata in <a href="https://daveabrock.com/2020/12/13/blast-off-blazor-cosmos?ref=daveabrock.com">a serverless Cosmos DB instance</a>. Feel free to read those links to learn more.</p><p>With the images in place, we’re going to build the image gallery. It’s responsive and will look good on devices of any size.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/image-gallery-view.png" class="kg-image" alt="Our slow site" loading="lazy" width="2000" height="1600" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/image-gallery-view.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/image-gallery-view.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/image-gallery-view.png 1600w, https://www.daveabrock.com/content/images/2021/05/image-gallery-view.png 2128w" sizes="(min-width: 720px) 720px"></figure><p>All code <a href="https://github.com/daveabrock/NASAImageOfDay?ref=daveabrock.com">is on GitHub</a>.</p><h2 id="customize-the-service-layer">Customize the service layer</h2><p>In previous posts, to get up and running we fetched a random image. To make things more interesting, we’re going to fetch images from the last 90 days. (In future posts, we’ll work on infinite scrolling and searching and filtering.) This requires updates to our Azure Function. We’ll ask for a <code>days</code> query string parameter that allows the caller to request up to 90 days of images. For example, if we call <code>api/assets/img?days=90</code>, we get images from the last 90 days.</p><p>I’ve added logic to verify and grab the <code>days</code>, make sure it’s in the appropriate range, then query Cosmos for the data itself.</p><pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.CosmosRepository;
using Data;
using System.Transactions;
using System.Collections.Generic;

namespace Api
{
    public class ImageGet
    {
        readonly IRepository&lt;Image&gt; _imageRepository;

        public ImageGet(IRepository&lt;Image&gt; imageRepository) =&gt; _imageRepository = imageRepository;

        [FunctionName("ImageGet")]
        public IActionResult Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "image")] HttpRequest req,
            ILogger log)
        {

            bool hasDays = int.TryParse(req.Query["days"], out int days);
            log.LogInformation($"Requested images from last {days} days.");

            if (!hasDays &amp;&amp; (days &lt;= 1 || days &gt; 90))
                return new BadRequestResult();

            ValueTask&lt;IEnumerable&lt;Image&gt;&gt; imageResponse;
            imageResponse = _imageRepository.GetAsync
                 (img =&gt; img.Date &gt; DateTime.Now.AddDays(-days));

            return new OkObjectResult(imageResponse.Result);
        }
    }
}
</code></pre><p>In the <code>ApiClientService</code> class in the <code>Client</code> project, update the call to take in the <code>days</code>. We’ll also order the images descending (newest to oldest):</p><pre><code>public async Task&lt;IEnumerable&lt;Image&gt;&gt; GetImageOfDay(int days)
{
    try
    {
        var client = _clientFactory.CreateClient("imageofday");
        var images = await client.GetFromJsonAsync
                &lt;IEnumerable&lt;Image&gt;&gt;($"api/image?days={days}");
                return images.OrderByDescending(img =&gt; img.Date);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex.Message, ex);
    }

     return null;
}
</code></pre><p>Now, in the code for the <code>Images</code> component, at <code>Images.razor.cs</code>, change the call to pass in the days:</p><pre><code class="language-csharp">protected override async Task OnInitializedAsync()
{
    _images = await ApiClientService.GetImageOfDay(days: 90);
}
</code></pre><h2 id="update-images-component-to-list-our-image-collection">Update Images component to list our image collection</h2><p>So, how should we lay out our images? I’d like to list them left-to-right, top-to-bottom. Luckily, I can use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout?ref=daveabrock.com">CSS grid layouts</a>. We can define how we want to lay out our rows and columns, and grid can handle how they render when the user’s window size is at different dimensions.</p><p>Using Tailwind CSS, I’m going to add a little bit of padding. Then, I’ll have one column on small devices, two columns on medium devices, and three columns on large and extra-large devices.</p><pre><code class="language-html">&lt;div class="p-2 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3"&gt;
&lt;/div&gt;
</code></pre><p>In between the <code>&lt;div&gt;</code>’s, we’ll iterate through our images and display them. We could handle the rendering here, but that’s asking for maintenance headaches and won’t give you any reusability options. The advantage of Blazor is in its component model. Let’s build a reusable component.</p><p>We can pass parameters to our components, and here we’ll want to pass down our <code>Image</code> model. Here’s how we’ll use the new component from the <code>Images</code> page, then:</p><pre><code class="language-html">&lt;div class="p-2 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3"&gt;
    @foreach (var image in _images)
    {
        &lt;ImageCard ImageDetails="image" /&gt;
    }
 &lt;/div&gt;
</code></pre><h2 id="create-a-reusable-imagecard-component">Create a reusable ImageCard component</h2><p>Now, in <code>Pages</code>, create two files: <code>ImageCard.razor</code>, and <code>ImageCard.razor.cs</code>. In the <code>.cs</code> file, use the <code>[Parameter]</code> attribute to pass down the <code>Image</code>. (We’ll likely add much more to this component, so are writing a partial class.)</p><pre><code class="language-csharp">using Microsoft.AspNetCore.Components;

namespace Client.Pages
{
    partial class ImageCard : ComponentBase
    {
        [Parameter]
        public Data.Image ImageDetails { get; set; }
    }
}
</code></pre><p>How will our new component look? As you can imagine, a lot of the work is in designing the layout. There’s a lot of different sized images, and I spent a lot of time getting it to work. Even though we aren’t going deep on Tailwind CSS in these posts, it’s worth mentioning here. (Also, much thanks to <a href="https://twitter.com/buhakmeh?ref=daveabrock.com">Khalid Abuhakmeh</a> for lending a hand.)</p><p>In the outer <code>&lt;div&gt;</code>, we’re giving the card a large shadow and some margin:</p><pre><code class="language-html">&lt;div class="m-6 rounded overflow-hidden shadow-lg"&gt;
&lt;/div&gt;
</code></pre><p>Then we’ll render our image, and assign the alternate tag to the title. It’s all in our model. We’re saying here it’ll fill the entire width of the card, only reach a specified height, and use <code>object-cover</code>, which <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit?ref=daveabrock.com">uses the <code>cover</code> value from the <code>object-fit</code> CSS property</a>. It maintains an image’s aspect ratio as an image is resized.</p><pre><code class="language-html">&lt;div class="m-6 rounded overflow-hidden shadow-lg"&gt;
    &lt;img class="w-full h-48 object-cover" src="@ImageDetails.Url" alt="@ImageDetails.Title" /&gt;
&lt;/div&gt;
</code></pre><p>In the rest of the markup, we do the following:</p><ul><li>We have an <code>IsNew</code> property on our model that we use to apply a <code>New</code> badge if an image is newer than three days old.</li><li>If so, we give it a teal background and darker teal text, and apply some effects to it. We use flexbox to align it appropriately. If it isn’t new, we make sure things are aligned appropriately without the badge.</li><li>Finally, we display the <code>Title</code>. We use the <code>truncate</code> property, which gives long titles <code>...</code> at the end. This way, the cards don’t align differently depending on how many lines of text the title consumes.</li></ul><pre><code class="language-html">&lt;div class="m-6 rounded overflow-hidden shadow-lg"&gt;
        &lt;img class="w-full h-48 object-cover" src="@ImageDetails.Url" alt="@ImageDetails.Title" /&gt;
        &lt;div class="p-6"&gt;
            &lt;div class="flex items-baseline"&gt;
                @if (ImageDetails.IsNew)
                {
                    &lt;div class="flex items-baseline"&gt;
                        &lt;span class="inline-block bg-teal-200 text-teal-800 text-xs px-2 rounded-full
                      uppercase font-semibold tracking-wide"&gt;New&lt;/span&gt;
                        &lt;div class="ml-2 text-gray-600 text-md-left uppercase font-semibold tracking-wide"&gt;
                            @ImageDetails.Date.ToLongDateString()
                        &lt;/div&gt;
                    &lt;/div&gt;
                }
                else
                {
                    &lt;div class="text-gray-600 text-md-left uppercase font-semibold tracking-wide"&gt;
                        @ImageDetails.Date.ToLongDateString()
                    &lt;/div&gt;
                }

            &lt;/div&gt;
            &lt;h3 class="mt-1 font-semibold text-2xl leading-tight truncate"&gt;@ImageDetails.Title&lt;/h3&gt;
        &lt;/div&gt;
&lt;/div&gt;
</code></pre><p>Here’s how a card looks with the <code>New</code> badge:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/new-badge.png" class="kg-image" alt="The card with a new badge" loading="lazy" width="700" height="539" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/new-badge.png 600w, https://www.daveabrock.com/content/images/2021/05/new-badge.png 700w"></figure><p>And again, here’s how the page looks. Check it out <a href="https://www.blastoffwithblazor.com/assets/img?ref=daveabrock.com">live at <em>blastoffwithblazor.com</em> as well</a>!</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/image-gallery-view-1.png" class="kg-image" alt="Our slow site" loading="lazy" width="2000" height="1600" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/image-gallery-view-1.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/image-gallery-view-1.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/image-gallery-view-1.png 1600w, https://www.daveabrock.com/content/images/2021/05/image-gallery-view-1.png 2128w" sizes="(min-width: 720px) 720px"></figure><p>For comparison, here’s how it looks on an iPhone X.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/iphone-cards.png" class="kg-image" alt="Our slow site" loading="lazy" width="552" height="1017"></figure><h2 id="wrap-up">Wrap up</h2><p>In this post, we showed off how to query images from our Cosmos DB and display our images using a responsive layout. Along the way, we learned how to pass parameters to reusable components.</p><p>In future posts, we’ll work on infinite scrolling, clicking an image for more details, and querying and searching the data.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Integrate Cosmos DB with Blazor WebAssembly ]]></title>
        <description><![CDATA[ So far in our series, we’ve walked through the intro
[https://daveabrock.com/2020/10/26/blast-off-blazor-intro], wrote our first
component [https://daveabrock.com/2020/10/28/blast-off-blazor-404-page], 
dynamically updated the HTML head from a component
[https://daveabrock.com/2020/11/08/blast-off-blazor-update-head], and isolated
our service dependencies
[https: ]]></description>
        <link>https://www.daveabrock.com/2020/12/13/blast-off-blazor-cosmos/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 12 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1592561199818-6b69d3d1d6e2?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGFzdHJvbmF1dHxlbnwwfHx8fDE2MTk4MzM2NDk&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>, and <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolated our service dependencies</a>.</p><p>It’s time to address the elephant in the room—why is the image loading so slow?</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/SetTitleBar-1.gif" class="kg-image" alt="Our slow site" loading="lazy" width="1042" height="1080"></figure><p>There’s a few reasons for that. First, we have to wait for the app to load when we refresh the page–and with Blazor WebAssembly, we’re waiting for the .NET runtime to load. On top of that, we’re calling off to a REST API, getting the image source, and sending that to our view. That’s not incredibly efficient.</p><p>In this post, we’re going to correct both issues. We’ll first move the <code>Image</code> component to its own page, then we’re going to use a persistence layer to store and work with our images. This includes hosting our images on Azure Storage and accessing its details using the Azure Cosmos DB serverless offering. This will only help us as we’ll create components to search on and filter our data.</p><p>This post contains the following content.</p><ul><li><a href="#move-our-image-component-to-its-own-page">Move our Image component to its own page</a></li><li><a href="#integrate-cosmos-db-with-our-application">Integrate Cosmos DB with our application</a></li><li><a href="#update-our-tests">Update our tests</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="move-our-image-component-to-its-own-page">Move our Image component to its own page</h2><p>To move our <code>Image</code> component away from the default <code>Index</code> view, rename your <code>Index.razor</code> and <code>Index.razor.cs</code> files to <code>Image.razor</code> and <code>Image.razor.cs</code>.</p><p>In the <code>Image.razor</code> file, change the route from <code>@page "/"</code> to <code>@page "/image"</code>. That keeps it as a routable component, meaning it’ll render whenever we browse to <code>/image</code>.</p><p>Then, in <code>Image.razor.cs</code>, make sure to rename the partial class to <code>Image</code>.</p><p>Here’s how <code>Image.razor.cs</code> looks now:</p><pre><code class="language-csharp">using Client.Services;
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;

namespace Client.Pages
{
    partial class Image : ComponentBase
    {
        Data.Image _image;

        [Inject]
        public IApiClientService ApiClientService { get; set; }

        private static string FormatDate(DateTime date) =&gt; date.ToLongDateString();

        protected override async Task OnInitializedAsync()
        {
            _image = await ApiClientService.GetImageOfDay();
        }
    }
}
</code></pre><h3 id="create-a-new-home-component">Create a new Home component</h3><p>With that in place, let’s create a new <code>Home</code> component. Right now, it’ll welcome users to the site and point them to our images component. (If you need a refresher on how the <code>NavigationManager</code> works, check out <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com#our-first-shared-component">my previous post on the topic</a>.)</p><pre><code class="language-html">@page "/"
@inject NavigationManager Navigator

&lt;div class="flex justify-center"&gt;
    &lt;div class="max-w-md rounded overflow-hidden shadow-lg m-12"&gt;
        &lt;h1 class="text-4xl m-6"&gt;Welcome to Blast Off with Blazor&lt;/h1&gt;
        &lt;img class="w-full" src="images/armstrong.jpg" /&gt;

        &lt;p class="m-4"&gt;
            This is a project to sample various Blazor features and functionality.

            We'll have more soon, but right now we are fetching random images.
        &lt;/p&gt;
        &lt;button class="text-center m-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
                @onclick="ToImagePage"&gt;
            🚀 Image of the Day
        &lt;/button&gt;
    &lt;/div&gt;
&lt;/div&gt;

@code {
    void ToImagePage() =&gt; Navigator.NavigateTo("/image");
} 
</code></pre><p>Here’s how the <code>Home</code> component looks now.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/new-splash-page.png" class="kg-image" alt="Our new index component" loading="lazy" width="1011" height="1519" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/new-splash-page.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/new-splash-page.png 1000w, https://www.daveabrock.com/content/images/2021/05/new-splash-page.png 1011w" sizes="(min-width: 720px) 720px"></figure><h2 id="integrate-cosmos-db-with-our-application">Integrate Cosmos DB with our application</h2><p>With our first fix out of the way, it’s now time to speed up our image loading time. I’m going to do this in two ways:</p><ul><li>Store the images statically in Azure Storage</li><li>Store image metadata, including the Azure Storage URLs in Cosmos DB</li></ul><p>In the past, Cosmos has been incredibly expensive and wouldn’t have been worth the cost for this project. With a new serverless offering (now in preview), it’s a lot more manageable and can easily be run under my monthly Azure credits. While Cosmos excels with intensive, globally-distributed workloads, I’m after a fully-managed NoSQL offering that’ll allow me flexibility if my schema needs change.</p><p>In this post, I won’t show you how to create a Cosmos instance, upload our images to Azure Storage, then create a link between the two. This is all <a href="https://daveabrock.com/2020/11/25/assets/img-azure-blobs-cosmos?ref=daveabrock.com">documented in a recent post</a>. After I have the data set up, I need to understand how to access it from my application. That’s what we’ll cover.</p><p>Now, I <em>could</em> <a href="https://docs.microsoft.com/azure/cosmos-db/sql-api-get-started?ref=daveabrock.com">use the Azure Cosmos DB C# client</a> to work with Cosmos. There’s a lot of complexities here, and I don’t need any of that business. I need it for basic CRUD operations. I’m a fan of <a href="https://twitter.com/davidpine7?ref=daveabrock.com">David Pine</a>’s <a href="https://devblogs.microsoft.com/cosmosdb/azure-cosmos-db-repository-net-sdk-v-1-0-4/?ref=daveabrock.com">Azure Cosmos DB Repository .NET SDK</a>, and will be using it here. This allows me to maintain the abstraction layer between the API and the client application, and is super easy to work with.</p><h3 id="update-the-api">Update the API</h3><p>After <a href="https://www.nuget.org/packages/Microsoft.Azure.Cosmos?ref=daveabrock.com">adding the NuGet package</a> to my <code>Api</code> and <code>Data</code> projects, I can start to configure it. There’s a few different ways to wire up your Cosmos details—check out <a href="https://github.com/IEvangelist/azure-cosmos-dotnet-repository?ref=daveabrock.com">the readme</a> for details—I’ll use the <code>Startup</code>.</p><p>Here’s the <code>Configure</code> method for my Azure Function in the <code>Api</code> project:</p><pre><code class="language-csharp">public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddCosmosRepository(
        options =&gt;
        {
            options.CosmosConnectionString = "my-connection-string";
            options.ContainerId = "image";
            options.DatabaseId = "APODImages";
        });
};
</code></pre><p>Next, I’ll need to make some changes to the model. Take a look and I’ll describe after:</p><pre><code class="language-csharp">using Microsoft.Azure.CosmosRepository;
using Newtonsoft.Json;
using System;

namespace Data
{
    public class Image : Item
    {
        [JsonProperty("title")]
        public string Title { get; set; }

        [JsonProperty("copyright")]
        public string Copyright { get; set; }

        [JsonProperty("date")]
        public DateTime Date { get; set; }

        [JsonProperty("explanation")]
        public string Explanation { get; set; }

        [JsonProperty("url")]
        public string Url { get; set; }
    }
}
</code></pre><p>You’ll see that the model now inherits from <code>Item</code>, which is required by the project. It contains an <code>Id</code>, a <code>Type</code> (for filtering implicitly on your behalf), and a partition key property. I’m also using <code>JsonProperty</code> attributes to match up with the Cosmos fields. Down the line, I might split models between my app and my API but this should work for now.</p><p>Now, in <code>ImageGet.cs</code>, I can call off to Cosmos quite easily. Here I’m calling off to my Cosmos instance. I can query by a random date.</p><pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.CosmosRepository;
using Data;

namespace Api
{
    public class ImageGet
    {
        readonly IRepository&lt;Image&gt; _imageRepository;

        public ImageGet(IRepository&lt;Image&gt; imageRepository) =&gt; _imageRepository = imageRepository;

        [FunctionName("ImageGet")]
        public async Task&lt;IActionResult&gt; Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "image")] HttpRequest req,
            ILogger log)
        {
            var imageResponse = _imageRepository.GetAsync
                (img =&gt; img.Date == GetRandomDate());
            return new OkObjectResult(imageResponse.Result);
        }

        private static DateTime GetRandomDate()
        {
            var random = new Random();
            var startDate = new DateTime(1995, 06, 16);
            var range = (DateTime.Today - startDate).Days;
            return startDate.AddDays(random.Next(range));
        }
    }
}
</code></pre><h3 id="update-the-client-app">Update the client app</h3><p>In our <code>ApiClientService</code>, I’ll need to slightly modify my <code>GetImageOfDay</code> method. The call returns an <code>IEnumerable&lt;Image&gt;</code>, so I’ll just grab the result.</p><pre><code class="language-csharp">public async Task&lt;Image&gt; GetImageOfDay()
{
    try
    {
        var client = _clientFactory.CreateClient("imageofday");
        var image = await client.GetFromJsonAsync&lt;IEnumerable&lt;Image&gt;&gt;("api/image");
        return image.First();
    }
    catch (Exception ex)
    {
        _logger.LogError(ex.Message, ex);
    }

    return null;
}
</code></pre><p>The images are now loading much faster!</p><h2 id="update-our-tests">Update our tests</h2><p>Thanks to successfully isolating our service last time, the tests for the <code>Image</code> component don’t need much fixing. Simply changing the component to <code>Image</code> instead of <code>Index</code> does the trick:</p><pre><code class="language-csharp">[Fact]
public void ImageOfDayComponentRendersCorrectly()
{
    var mockClient = new Mock&lt;IApiClientService&gt;();
    mockClient.Setup(i =&gt; i.GetImageOfDay()).ReturnsAsync(GetImage());

    using var ctx = new TestContext();
    ctx.Services.AddSingleton(mockClient.Object);

    IRenderedComponent&lt;Client.Pages.Image&gt; cut = ctx.RenderComponent&lt;Client.Pages.Image&gt;();
    var h1Element = cut.Find("h1").TextContent;
    var imgElement = cut.Find("img");
    var pElement = cut.Find("p");

    h1Element.MarkupMatches("My Sample Image");
    imgElement.MarkupMatches(@"&lt;img src=""https://nasa.gov"" 
        class=""rounded-lg h-500 w-500 flex items-center justify-center""&gt;");
    pElement.MarkupMatches(@"&lt;p class=""text-2xl""&gt;Wednesday, January 1, 2020&lt;/p&gt;");
}
</code></pre><p>We can also add a quick test to our <code>Home</code> component in a new <code>HomeTest</code> file, which is similar to how we did our <code>NotFound</code> component:</p><pre><code class="language-csharp">[Fact]
public void IndexComponentRendersCorrectly()
{
    using var ctx = new TestContext();
    var cut = ctx.RenderComponent&lt;Home&gt;();
    var h1Element = cut.Find("h1").TextContent;
    var buttonElement = cut.Find("button").TextContent;

    h1Element.MarkupMatches("Welcome to Blast Off with Blazor");
    buttonElement.MarkupMatches("🚀 Image of the Day");
}
</code></pre><h2 id="wrap-up">Wrap up</h2><p>In this post, we worked on speeding up the loading of our images. We first moved our <code>Image</code> component off the home page, then integrated Cosmos DB into our application. Finally, we cleaned up our tests.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #29: More on route-to-code and some Kubernetes news ]]></title>
        <description><![CDATA[ This week, we dig deep on route-to-code and discuss some Kubernetes news. ]]></description>
        <link>https://www.daveabrock.com/2020/12/12/dotnet-stacks-29/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 11 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-16.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter, The .NET Stacks. It was originally sent to subscribers on December 7, 2020. Subscribe at the bottom of this post to get the content right away!</em></p><p>Happy Monday! Here’s what we’re talking about this week:</p><ul><li>Digging deeper on “route-to-code”</li><li>Kubernetes is deprecating Docker … what?</li><li>Last week in the .NET world</li></ul><h2 id="-digging-deeper-on-route-to-code-">🔭 Digging deeper on “route-to-code”</h2><p>Last week, I talked about <a href="https://daveabrock.com/2020/12/05/dotnet-stacks-28?ref=daveabrock.com#the-future-of-aspnet-core-mvc-apis">the future of writing APIs for ASP.NET Core MVC</a>. The gist: there’s a new initiative (Project Houdini) coming to move MVC productivity features to the core of the stack, and part of that is generating imperative APIs for you at compile time using source generation.</p><p>This leverages a way to write slim APIs in ASP.NET Core without the bloat of the MVC framework: it’s called “route-to-code.” We <a href="https://daveabrock.com/2020/10/09/dotnet-stacks-20?ref=daveabrock.com#use-route-to-code-with-aspnet-core">talked about it in early October</a>. I thought it’d be fun to migrate a simple MVC CRUD API to this model, and <a href="https://daveabrock.com/2020/12/04/migrate-mvc-to-route-to-code?ref=daveabrock.com">I wrote about it this week</a>.</p><p>As I wrote, this isn’t meant to be an MVC replacement, but a solution for simple JSON APIs. It does <em>not</em> support model binding or validation, content negotiation, or dependency injection from constructors. Most times, though, you’re wanting to separate business logic from your execution context—it’s definitely worth a look.</p><p>Here’s me using an in-memory Entity Framework Core database to get some bands:</p><pre><code class="language-csharp">endpoints.MapGet("/bands", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();
    var bands = repository.Bands.ToListAsync();
    await context.Response.WriteAsJsonAsync(bands);
});
</code></pre><p>There’s no framework here, so instead of using DI to access my EF context, I get a service through the <code>HttpContext</code>. Then, I can use helper methods that let me read from and write to my pipe. Pretty slick.</p><p>Here’s me getting a record by ID:</p><pre><code class="language-csharp">endpoints.MapGet("/bands/{id}", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();
    var id = context.Request.RouteValues["id"];
    var band = await repository.Bands.FindAsync(Convert.ToInt32(id));

    if (band is null)
    {
        context.Response.StatusCode = StatusCodes.Status404NotFound;
        return;
    }
    await context.Response.WriteAsJsonAsync(band);
});
</code></pre><p>The simplicity comes with a cost: it’s all very manual. I even have to convert the ID to an integer myself (not a big deal, admittedly).</p><p>How does a POST request work? I can check to see if the request is asking for JSON. With no framework or filters, my error checking is setting a status code and returning early. (I can abstract this out, obviously. It took awhile to get used to not having a framework to lean on.)</p><pre><code class="language-csharp">endpoints.MapPost("/bands", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();

    if (!context.Request.HasJsonContentType())
    {
        context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
        return;
    }

    var band = await context.Request.ReadFromJsonAsync&lt;Band&gt;();
    await repository.SaveChangesAsync();
    await context.Response.WriteAsJsonAsync(band);
});
</code></pre><p>In the doc, Microsoft <a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com#notable-missing-features-compared-to-web-api">will be the first to tell you</a> it’s for the simplest scenarios. It’ll be interesting to see what improvements come: will mimicking DI become easier? I hope so.</p><h2 id="-kubernetes-is-deprecating-docker-what">🤯 Kubernetes is deprecating Docker … what?</h2><p>I know this is a .NET development newsletter, but these days you probably need at least a <em>passing</em> knowledge of containerization. To that end: this week, you may have heard something along the lines of “Kubernetes is deprecating Docker.” It sounds concerning, but <a href="https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/?ref=daveabrock.com">Kubernetes says you probably shouldn’t worry</a> and Docker <a href="https://www.docker.com/blog/what-developers-need-to-know-about-docker-docker-engine-and-kubernetes-v1-20/?ref=daveabrock.com">is saying the same</a>.</p><p>Still, it’s true: Kubernetes is deprecating Docker as a container runtime after v1.20—currently planned for late 2021.</p><p>From a high level, I think Google’s <a href="https://twitter.com/kelseyhightower/status/1334920845999783937?ref=daveabrock.com">Kelsey Hightower summed it up best</a>:</p><blockquote>Think of it like this – Docker refactored its code base, broke up the monolith, and created a new service, containerd, which both Kubernetes and Docker now use for running containers.</blockquote><p>Docker isn’t a magical “make me a container” button—it’s an entire tech stack. Inside of that is <a href="https://www.docker.com/blog/what-is-containerd-runtime/?ref=daveabrock.com">a container runtime</a>, <em>containerd</em>. It contains a lot of bells and whistles for us when doing development work, but k8s doesn’t need it because it isn’t a person. (If it were, I’d like to have a chat.)</p><p>For k8s to get through this abstraction layer, it needs to use the Dockershim tool to get to <em>containerd</em>—yet another maintenance headache. Kubelets <a href="https://kubernetes.io/blog/2020/12/02/dockershim-faq/?ref=daveabrock.com">are removing Dockershims</a> at the end of 2021, which removes Docker support. When this change comes, you just need to change your container runtime from Docker to another supported runtime.</p><p>Because this addresses a different environment than most folks use with Docker, it shouldn’t matter—the install you’re using in dev is typically different than the runtime in your k8s cluster. This change would largely impact k8s administrators and not developers.</p><p>Hopefully this clears up some potential confusion. We don’t talk about Docker and Kubernetes often, but this was too important not to discuss. (I could hardly <em>contain</em> myself.)</p><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Niels Swimberghe <a href="https://swimburger.net/blog/dotnet/making-phone-calls-from-blazor-webassembly-with-twilio-voice?ref=daveabrock.com">makes phone calls from Blazor WebAssembly with Twilio Voice</a>. (And while you’re there, hover over the burger. You’re welcome.)</li><li>Steve Smith <a href="https://ardalis.com/avoid-wrapping-dbcontext-in-using/?ref=daveabrock.com">warns against wrapping DbContext in using, and other gotchas</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/understand-the-dotnet-five-runtime-environment?ref=daveabrock.com">writes about understanding the .NET 5 runtime environment</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>Claire Novotny <a href="https://devblogs.microsoft.com/dotnet/improving-debug-time-productivity-with-source-link?ref=daveabrock.com">shines a light on debug-time productivity with Source Link</a>.</li><li>.NET Core 2.1, 3.1, and 5.0 <a href="https://devblogs.microsoft.com/dotnet/net-core-updates-coming-to-microsoft-update?ref=daveabrock.com">updates are coming to Microsoft Update</a>.</li><li>Uno Platform 3.1 <a href="https://platform.uno/blog/uno-platform-3-1-released-linux-new-winui-controls-prism-8-0-and-more/?ref=daveabrock.com">is released</a>.</li><li>Scott Addie <a href="https://docs.microsoft.com/aspnet/core/whats-new/2020-11?ref=daveabrock.com">recaps what’s new in the ASP.NET Core docs for November 2020</a>.</li><li>Bri Achtman <a href="https://devblogs.microsoft.com/dotnet/ml-net-model-builder-november-updates?ref=daveabrock.com">writes about ML.NET Model Builder November updates</a>.</li><li>Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-november-2020-cumulative-update-preview-for-windows-10-2004-and-windows-server-version-2004?ref=daveabrock.com">releases the November 2020 cumulative update preview for .NET Framework</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>Just one community standup this week: Xamarin <a href="https://www.youtube.com/watch?v=7Gvr0d1vTQ4&ref=daveabrock.com">talks about .NET MAUI</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=sU9xwxY3Ikw&ref=daveabrock.com">talks to Dave Brock</a> (yes, that one) about C# 9.</li></ul><h3 id="-asp-net-core-blazor">😎 ASP.NET Core / Blazor</h3><ul><li>Dave Brock <a href="https://daveabrock.com/2020/12/04/migrate-mvc-to-route-to-code?ref=daveabrock.com">writes about simple JSON APIs with ASP.NET Core route-to-code</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2020/12/01/blazor-performance.aspx?ref=daveabrock.com">writes about reported performance degradation when moving from WinForms to Blazor</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-async-file-uploads?ref=daveabrock.com">writes about the pitfalls when working with async file uploads in ASP.NET Core</a>.</li><li>Jon Hilton <a href="https://www.telerik.com/blogs/how-to-pass-arguments-to-your-onclick-functions-blazor?ref=daveabrock.com">passes arguments to onclick functions in Blazor</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/complex-model-validation-in-blazor/?ref=daveabrock.com">writes about complex model validation in Blazor apps</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2020/12/03/securing-an-asp-net-core-api-which-uses-multiple-access-tokens/?ref=daveabrock.com">secures an ASP.NET Core API that uses multiple access tokens</a>.</li><li>Michael Shpilt <a href="https://oz-code.com/blog/net-c-tips/8-must-know-nuget-packages-asp-net-core-application?ref=daveabrock.com">writes about some must-know packages for ASP.NET Core</a>.</li></ul><h3 id="-net-5">🚀 .NET 5</h3><ul><li>Jonathan Allen <a href="https://www.infoq.com/news/2020/12/net-5-breaking-changes-2?ref=daveabrock.com">writes more about .NET 5 breaking changes</a>.</li><li>Eran Stiller <a href="https://www.infoq.com/news/2020/12/net-5-runtime-improvements?ref=daveabrock.com">writes about .NET 5 runtime improvements</a>.</li><li>Jonathan Allen <a href="https://www.infoq.com/news/2020/12/net-5-breaking-changes?ref=daveabrock.com">writes about .NET 5 breaking changes to the BCL</a>.</li><li>Antonio Laccardi <a href="https://www.infoq.com/news/2020/12/aspnet-core-improvement-dotnet-5?ref=daveabrock.com">writes about ASP.NET Core improvements in .NET 5</a>.</li><li>Norm Johnson <a href="https://aws.amazon.com/blogs/developer/net-5-aws-lambda-support-with-container-images?ref=daveabrock.com">writes about .NET 5 AWS Lambda support with container images</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Frank Boucher <a href="http://www.frankysnotes.com/2020/12/how-to-configure-secured-custom-domain.html?ref=daveabrock.com">configures a secured custom domain on an Azure Function or website</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2020/11/28/handling-events-inside-an-azure-function?ref=daveabrock.com">handles events inside an Azure Function</a>.</li><li>David Ramel <a href="https://visualstudiomagazine.com/articles/2020/11/30/cloud-functions-net.aspx?ref=daveabrock.com">writes how Google Cloud Functions supports .NET Core 3.1 but not .NET 5</a>.</li><li>Abel Wang and Isaac Levin <a href="https://devblogs.microsoft.com/devops/optimum-developer-productivity-github-visual-studio-code-azure?ref=daveabrock.com">write about dev productivity with GitHub, VS Code, and Azure</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2020/12/03/csharp-9-top-level-statements/?ref=daveabrock.com">writes about top-level statements in C# 9</a>, and also <a href="https://www.claudiobernasconi.ch/2020/12/04/csharp-8-switch-expressions/?ref=daveabrock.com">works through switch expressions in C# 8</a>.</li><li>Munib Butt <a href="https://www.c-sharpcorner.com/article/using-the-proxy-pattern-in-c-sharp/?ref=daveabrock.com">uses the proxy pattern in C#</a>.</li><li>Ian Russell <a href="https://www.softwarepark.cc/blog/2020/11/30/introduction-to-partial-function-application-in-f?ref=daveabrock.com">introduces partial function application in F#</a>.</li><li>Ian Griffiths <a href="https://endjin.com/blog/2020/12/dotnet-csharp-9-patterns-mechanism-over-intent.html?ref=daveabrock.com">shows the pitfalls of mechanism over intent with C# 9 patterns</a>.</li><li>Matthew Crews <a href="https://matthewcrews.com/blog/2020-12-04-the-under-appreciated-power-of-object-expressions/?ref=daveabrock.com">writes about object expressions in F#</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Sean Killeen <a href="https://seankilleen.com/2020/11/getting-started-with-powershell-core-in-windows-terminal/?ref=daveabrock.com">gets started with PowerShell Core in Windows Terminal</a>, and also <a href="https://seankilleen.com/2020/12/cool-things-i-learned-about-nunit-while-re-launching-the-docs/?ref=daveabrock.com">writes about things he’s learned about NUnit</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/?ref=daveabrock.com">uses Quartz.NET with ASP.NET Core and worker services</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>James Montemagno <a href="https://montemagno.com/dont-put-android-in-your-namespace-in-xamarin-apps/?ref=daveabrock.com">warns against using Android in your namespaces</a>, and also <a href="https://montemagno.com/build-your-first-for-ios-android-app-with-xamarin-and-visual-studio/?ref=daveabrock.com">gets you writing your first app for iOS and Android with Xamarin and Visual Studio</a>.</li><li>Yogeshwaran Mohan <a href="https://www.syncfusion.com/blogs/post/create-xamarin-marquee-control.aspx?ref=daveabrock.com">creates a marquee control</a>.</li><li>Nick Randolph <a href="https://nicksnettravels.builttoroam.com/net5-crossplatform?ref=daveabrock.com">explains the correlation between .NET 5, WinUI, and MAUI (Xamarin.Forms)</a>.</li><li>Matheus Castello <a href="https://microhobby.com.br/blog/2020/11/30/vs-code-xaml-preview-embedded-linux-dotnet-core/?ref=daveabrock.com">writes about Linux + .NET 5 + VS Code XAML Preview + Hot Reload running on embedded Linux</a>.</li></ul><h3 id="-design-architecture-and-best-practices">👍 Design, architecture and best practices</h3><ul><li>Kamil Grzybek <a href="http://www.kamilgrzybek.com/design/modular-monolith-domain-centric-design/?ref=daveabrock.com">continues his series on modular monoliths</a>.</li><li>Scott Brady reminds us: <a href="https://www.scottbrady91.com/OAuth/OAuth-is-Not-User-Authorization?ref=daveabrock.com">OAuth is not user authorization</a>.</li><li>Peter Vogel <a href="https://www.telerik.com/blogs/the-only-testing-that-matters-testing-through-eyes-of-user?ref=daveabrock.com">shows the advantages of end-to-end testing</a>.</li><li>Nathan Bennett <a href="https://www.bignerdranch.com/blog/graphql-versus-rest/?ref=daveabrock.com">compares GraphQL to REST</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/handling-duplicate-messages-idempotent-consumers/?ref=daveabrock.com">talks about handling duplicate messages</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The Changelog <a href="https://changelog.com/podcast/422?ref=daveabrock.com">talks about growing as a software engineer</a>.</li><li>The Stack Overflow podcast <a href="https://the-stack-overflow-podcast.simplecast.com/episodes/ensuring-your-software-is-ethical-might-save-you-money-in-the-long-run-ft7H842f?ref=daveabrock.com">explains why devs are increasing demanding ethics in tech</a>.</li><li>The 6 Figure Developer <a href="https://6figuredev.com/podcast/episode-172-rob-richardson-net-5-pipelines-testing/?ref=daveabrock.com">talks to Rob Richardson about .NET 5, pipelines, and testing</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>Jeff Fritz <a href="https://www.youtube.com/watch?v=bqujgzOaoE8&ref=daveabrock.com">works with Entity Framework Core</a>.</li><li>The ON.NET Show <a href="https://channel9.msdn.com/Shows/On-NET/Customizing-the-Graph-SDKs?ref=daveabrock.com">customizes the Graph SDKs</a> and <a href="https://www.youtube.com/watch?v=QmbU1vwBEp8&ref=daveabrock.com">discusses microcontrollers with the Meadow IoT platform</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Getting-Started-with-DevOps-for-Azure-SQL?ref=daveabrock.com">gets started with DevOps for Azure SQL</a>.</li><li>The Loosely Coupled Show <a href="https://www.youtube.com/watch?v=1ps4QJpUfVc&ref=daveabrock.com">talks about the difficulties of caching</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use local function attributes with C# 9 ]]></title>
        <description><![CDATA[ In this quick post, I introduce how to use attributes on local functions in C# 9. ]]></description>
        <link>https://www.daveabrock.com/2020/12/09/local-function-attributes-c-sharp-9/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe7a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 08 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1615309661755-816dcd80bcd3?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxkZWJ1Z3xlbnwwfHx8fDE2MTk4MzM3MjU&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>If you look at what’s new in C# 9, you’ll see records, init-only properties, and top-level statements <a href="https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-9?ref=daveabrock.com">get all the glory</a>. And that’s fine, because they’re great. At the end of the bulleted list, I noticed <a href="https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-9?ref=daveabrock.com">support for local attributes on local functions</a>.</p><p>When it comes to local functions, with C# 9 you can <a href="https://docs.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-9.0/local-function-attributes?ref=daveabrock.com">apply attributes to function declarations, parameters, and type parameters</a>.</p><p>The most common use case I’ve seen is using the <code>ConditionalAttribute</code>. This attribute is used for checking conditional compilation symbols—instead of using <code>#define DEBUG</code> regions, for example, you can do it here. You can declare multiple attributes, just like for a “normal” method. For example:</p><pre><code class="language-csharp">static void Main(string[] args)
{
    [Conditional("DEBUG")]
    [Conditional("BETA")]
    static void DoSuperSecretStuff()
    {
        Console.WriteLine("This only is executed in debug or beta mode.");
    }

    DoSuperSecretStuff();
}
</code></pre><p>If you want to work with the <code>ConditionalAttribute</code> the methods must be both <code>static</code> and <code>void</code>.</p><p>Of course, you can work with any kind of attributes. In the GruutBot project (<a href="https://daveabrock.com/2020/07/28/azure-bot-service-cognitive-services?ref=daveabrock.com">which I showcased here</a>), there’s a local function that has a switch expression to determine Gruut’s emotion:</p><pre><code class="language-csharp">static string GetReplyText(TextSentiment sentiment) =&gt; sentiment switch
{
    TextSentiment.Positive =&gt; "I am Gruut.",
    TextSentiment.Negative =&gt; "I AM GRUUUUUTTT!!",
    TextSentiment.Neutral =&gt; "I am Gruut?",
    _ =&gt; "I. AM. GRUUUUUT"
};
</code></pre><p>Here I can go wild with a few more attributes:</p><pre><code class="language-csharp">[Obsolete]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
static string GetReplyText(TextSentiment sentiment) =&gt; sentiment switch
{
    TextSentiment.Positive =&gt; "I am Gruut.",
    TextSentiment.Negative =&gt; "I AM GRUUUUUTTT!!",
    TextSentiment.Neutral =&gt; "I am Gruut?",
    _ =&gt; "I. AM. GRUUUUUT"
};
</code></pre><p>The <code>ObsoleteAttribute</code> <a href="https://docs.microsoft.com/dotnet/api/system.obsoleteattribute?view=net-5.0&ref=daveabrock.com">signifies to callers</a> that the function is no longer use (and will trigger a warning when invoked).</p><p>As for the <code>MethodImplAttribute</code>, it allows me to specify <code>AggressiveOptimization</code>. The details are a topic for another post, but from a high level: this method is JIT’ed when first called, and the JIT’ed code is always optimized—making it ineligible for tiered compilation.</p><p>This new local function support brings attributes to this scope, which is a welcome addition. These aren’t “new” attributes, but just the ability to do it in local functions now.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, I quickly showed you how to use local function attributes in C# 9. If you have any suggestions, please let me know!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Automate a Markdown links page with Pinboard and C# ]]></title>
        <description><![CDATA[ In this post, we generate a Markdown links page using Pinboard and C#. ]]></description>
        <link>https://www.daveabrock.com/2020/12/07/make-link-list-with-markdown-and-with-c-sharp/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe79</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 06 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1580656449548-a2278870021d?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHB1c2glMjBwaW58ZW58MHx8fHwxNjE5ODMzODQ0&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p><em>This is my contribution for the <a href="https://www.csadvent.christmas/?ref=daveabrock.com">C# Advent Calendar</a>, a collection of awesome C# posts throughout December. Check it out!</em></p><p>I run a weekly newsletter called <em>The .NET Stacks</em>. If you’ve read this blog for any period of time you know this, thanks to my shameless plugs. (Feel free <a href="https://dotnetstacks.com/?ref=daveabrock.com">to subscribe</a>!) I love it and enjoy writing it every week, but it can take up a lot of my time.</p><p>The biggest time spent is generating all the great community links. Luckily, I found a way to automate this process. I can click a button, and a console app writes all my links to my Markdown file. Then, all I have to do is fill in the rest of the newsletter.</p><p>It’s down to a two-step process, really: throughout the week, I add links to my Pinboard, then my app writes them to a Markdown file.</p><p>This post will show off how you can populate a Markdown links page using Pinboard and C#.</p><h2 id="how-i-curate-links">How I curate links</h2><p>The act of getting links has to be somewhat manual. I could say “whenever Person X posts, save it” but what if this person goes nuts and writes a post criticizing Santa Claus? My links are curated—while I don’t agree with everything I share, I do want them to be relevant and useful. After getting links from my various RSS feeds and link aggregators, I can start the automation.</p><p>Where do I store my bookmarks? I’m a big fan <a href="https://pinboard.in/?ref=daveabrock.com">of Pinboard</a>. For not even $2 a month, it’s a no frills, fast, and secure way to save bookmarks. No ads, no tracking, and a great feature set. And it <a href="https://pinboard.in/api/?ref=daveabrock.com">comes with an API</a>! I knew this would save me hours a month and it makes the investment well worth it.</p><p>After exploring the API docs, I found a hacky—but useful!—way to save me loads of time.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/markdown-link.png" class="kg-image" alt="A link in Pinboard" loading="lazy" width="807" height="486" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/markdown-link.png 600w, https://www.daveabrock.com/content/images/2021/05/markdown-link.png 807w" sizes="(min-width: 720px) 720px"></figure><p>These are all retrievable fields from the API. The <code>title</code>, which is my name, is anything before the link and the <code>description</code> is my link text.</p><p>After I get all my links in, usually by Sunday, I’m ready to generate the links. Let’s look at how I make that happen.</p><h2 id="use-c-to-generate-markdown-links-page">Use C# to generate Markdown links page</h2><p>This is all done with a simple console app. It isn’t enterprise-ready; it’s for me. So I didn’t go crazy with any of it—the point of this is something quick to get my time back.</p><p>To interact with the Pinboard API, I’m using the <a href="https://github.com/shrayasr/pinboard.net?ref=daveabrock.com">Pinboard.net NuGet package</a>, a wonderful C# wrapper that makes connecting to the API so easy. Thanks to <a href="https://github.com/shrayasr?ref=daveabrock.com">Shrayas Rajagopal</a> for your work on this!</p><p>I was able to use <a href="https://daveabrock.com/2020/07/09/c-sharp-9-top-level-programs?ref=daveabrock.com">C# 9 top-level programs</a> to avoid the <code>Main</code> method ceremony.</p><p>At the top of the program, I do the following:</p><pre><code class="language-csharp">using var pb = new PinboardAPI("my-api-key");
var bookmarksList = await pb.Posts.All();
await WriteMarkdownFile(bookmarksList);
</code></pre><p>I connect to Pinboard using my API key and get all my bookmarks (referred to as <code>Posts</code>). Then, everything happens in my <code>WriteMarkdownFile</code> method.</p><p>I define the <code>filePath</code> on my system, and include today’s date in the name.</p><pre><code class="language-csharp">var filePath = $"C:\\path\\to\\site\\_drafts\\{DateTime.Now:yyyy-MM-dd}-dotnet-stacks.markdown";
</code></pre><p>All my links are categorized by tags. To avoid hardcoding, I have a <code>Tags</code> class to store the tag names (what I use in Pinboard) and the heading (what is in the newsletter):</p><pre><code class="language-csharp">public static class Tags
{
    public const string AnnouncementsHeading = "📢 Announcements";
    public const string AnnouncementsTag = "Announcements";

    public const string BlazorHeading = "😎 Blazor";
    public const string BlazorTag = "Blazor";

    // and so on and so forth
}
</code></pre><p>Back to the <code>WriteMarkdownFile</code> method, I store these in a dictionary. Depending on the week, I change the order of these, so I want that flexibility. (I could have sorting logic, <em>I suppose</em>.)</p><pre><code class="language-csharp">var tagInfo = new Dictionary&lt;string, string&gt;
{
    { Tags.AnnouncementsHeading, Tags.AnnouncementsTag },
    { Tags.CommunityHeading, Tags.CommunityTag },
    { Tags.BlazorHeading, Tags.BlazorTag },
    { Tags.DotNetCoreHeading, Tags.DotNetCoreTag },
    { Tags.CloudHeading, Tags.CloudTag },
    { Tags.LanguagesHeading, Tags.LanguagesTag },
    { Tags.ToolsHeading, Tags.ToolsTag },
    { Tags.XamarinHeading, Tags.XamarinTag },
    { Tags.PodcastsHeading, Tags.PodcastsTag },
    { Tags.VideoHeading, Tags.VideoTag }
};
</code></pre><p>Using a classic <code>StringBuilder</code>, I start to write out the file. I begin with my Jekyll front matter and the beginning heading, which is always the same:</p><pre><code>var sb = new StringBuilder("---");
sb.AppendLine();
sb.AppendLine($"date: \"{DateTime.Now:yyyy-MM-dd}\"");
sb.AppendLine("title: \"The .NET Stacks: &lt;fill in later&gt;\"");
sb.AppendLine("tags: [dotnet-stacks]");
sb.AppendLine("comments: false");
sb.AppendLine("---");
sb.AppendLine();

sb.AppendLine("## 🌎 Last week in the .NET world");
sb.AppendLine();
sb.AppendLine("### 🔥 The Top 3");
sb.AppendLine();
</code></pre><p>Here’s the fun part, where I print out all the bookmarks:</p><pre><code class="language-csharp">foreach (var entry in tagInfo)
{
    sb.AppendLine($"### {entry.Key}");
    sb.AppendLine();

    foreach (string bookmark in GetBookmarksForTag(entry.Value, bookmarksList))
    {
        sb.AppendLine($"- {bookmark}");
    }

    sb.AppendLine();
}
</code></pre><p>For each tag in the dictionary, I create a heading with the tag text, then do a line break. Then, for each <code>bookmark</code> object, I have a method that retrieves a filtered list based on the tag. For each bookmark, I construct a string with how I want to format the link, then add it to a list.</p><pre><code class="language-csharp">static string[] GetBookmarksForTag(string tag, AllPosts allBookmarks)
{
    var filteredBookmarks = allBookmarks.Where(b =&gt; b.Tags.Contains(tag));
    var filteredList = new List&lt;string&gt;();

    foreach (var bookmark in filteredBookmarks)
    {
        var stringToAdd = $"{bookmark.Description} [{bookmark.Extended}]({bookmark.Href}).";
        filteredList.Add(stringToAdd);
    }

    return filteredList.ToArray();
}
</code></pre><p>Once I’m done with all the tags, I use a <code>TextWriter</code> to write to the file itself.</p><pre><code class="language-csharp">static string[] GetBookmarksForTag(string tag, AllPosts allBookmarks)
{
    var filteredBookmarks = allBookmarks.Where(b =&gt; b.Tags.Contains(tag));
    var filteredList = new List&lt;string&gt;();

    foreach (var bookmark in filteredBookmarks)
    {
        var stringToAdd = $"{bookmark.Description} [{bookmark.Extended}]({bookmark.Href}).";
        filteredList.Add(stringToAdd);
    }

    return filteredList.ToArray();
}
</code></pre><p>In just 76 lines of code, I was able to come up with something that saves me a ridiculous amount of time. There are other improvements to be made, like storing backups to Azure Storage, but I like it.</p><p>Here’s the full code, if you’d like:</p><pre><code class="language-csharp">using pinboard.net;
using pinboard.net.Models;
using PinboardToMarkdown;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using var pb = new PinboardAPI("my_api_key");
var bookmarksList = await pb.Posts.All();
await WriteMarkdownFile(bookmarksList);

static async Task WriteMarkdownFile(AllPosts bookmarksList)
{
    var filePath = $"C:\\path\\to\\site\\_drafts\\{DateTime.Now:yyyy-MM-dd}-dotnet-stacks.markdown";

    var tagInfo = new Dictionary&lt;string, string&gt;
    {
          { Tags.AnnouncementsHeading, Tags.AnnouncementsTag },
          { Tags.CommunityHeading, Tags.CommunityTag },
          { Tags.BlazorHeading, Tags.BlazorTag },
          { Tags.DotNetCoreHeading, Tags.DotNetCoreTag },
          { Tags.CloudHeading, Tags.CloudTag },
          { Tags.LanguagesHeading, Tags.LanguagesTag },
          { Tags.ToolsHeading, Tags.ToolsTag },
          { Tags.XamarinHeading, Tags.XamarinTag },
          { Tags.PodcastsHeading, Tags.PodcastsTag },
          { Tags.VideoHeading, Tags.VideoTag }
    };

    var sb = new StringBuilder("---");
    sb.AppendLine();
    sb.AppendLine($"date: \"{DateTime.Now:yyyy-MM-dd}\"");
    sb.AppendLine("title: \"The .NET Stacks: &lt;fill in later&gt;\"");
    sb.AppendLine("tags: [dotnet-stacks]");
    sb.AppendLine("comments: false");
    sb.AppendLine("---");
    sb.AppendLine();

    sb.AppendLine("## 🌎 Last week in the .NET world");
    sb.AppendLine();
    sb.AppendLine("### 🔥 The Top 3");
    sb.AppendLine();

    foreach (var entry in tagInfo)
    {
        sb.AppendLine($"### {entry.Key}");
        sb.AppendLine();

        foreach (string bookmark in GetBookmarksForTag(entry.Value, bookmarksList))
        {
            sb.AppendLine($"- {bookmark}");
        }

        sb.AppendLine();
    }

    await using TextWriter stream = new StreamWriter(filePath);
    await stream.WriteAsync(sb.ToString());
}

static string[] GetBookmarksForTag(string tag, AllPosts allBookmarks)
{
    var filteredBookmarks = allBookmarks.Where(b =&gt; b.Tags.Contains(tag));
    var filteredList = new List&lt;string&gt;();

    foreach (var bookmark in filteredBookmarks)
    {
        var stringToAdd = $"{bookmark.Description} [{bookmark.Extended}]({bookmark.Href}).";
        filteredList.Add(stringToAdd);
    }

    return filteredList.ToArray();
}
</code></pre><h2 id="wrap-up">Wrap up</h2><p>In this post, I showed how you can use Pinboard and C# to send links to a Markdown page automatically. I showed why I like to use Pinboard, and we also stepped through the code to see how it all works.</p><p>If you have any suggestions, please let me know!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks, #28: The future of MVC and themes of .NET 6 ]]></title>
        <description><![CDATA[ This week, we look at the future of APIs in ASP.NET Core MVC and the &quot;themes&quot; of .NET 6. ]]></description>
        <link>https://www.daveabrock.com/2020/12/05/dotnet-stacks-28/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe78</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 04 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-17.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter, The .NET Stacks. It was originally sent to subscribers on November 30, 2020. Subscribe at the bottom of this post to get the content right away!</em></p><p>Happy Monday to all. This week, we’ll be discussing:</p><ul><li>The future of ASP.NET Core MVC APIs</li><li>Check out the “themes” of .NET 6</li><li>.NET Q&amp;A: Not the Overflow you’re looking for</li><li>Last week in the .NET world</li></ul><h2 id="the-future-of-asp-net-core-mvc-apis">The future of ASP.NET Core MVC APIs</h2><p>This week, David Fowler <a href="https://www.youtube.com/watch?v=d9Bjg31VuHw&ref=daveabrock.com">stopped by the ASP.NET community standup</a> to talk about ASP.NET Core architecture. As you’d expect, it was quite informative. We learned how the team is addressing MVC, ASP.NET Core’s exception to the rule.</p><p>As ASP.NET Core has kept an eye on lightweight and modular services, MVC isn’t exactly a shining example of this concept. As with a lot of Microsoft tech, there are a lot of historical reasons for this—when thinking about MVC for ASP.NET Core, a lot of time was spent merging APIs and MVC web bits into one platform so performance analysis wasn’t given the light of day.</p><p>If you develop APIs with MVC, then, you’re paying a lot up front. When a lot of use cases are using it for CRUD operations over HTTP, do you need all the extension filters, formatters, and so on? Why pay for all of MVC if you aren’t using it? As said in the standup, we’re now looking at a “framework for framework authors” where all the abstractions aren’t used by 99% of developers.</p><p>Fowler and team are working on something called “Project Houdini”—an effort to “make MVCs disappear.” Don’t worry, MVC will always be around, but the effort revolves pushing MVC productivity features to the core of the stack, and not being a special citizen. Along the way, performance should improve. Fowler showed off a way to generate imperative APIs for you at compile time using source generation (allowing you to keep the traditional MVC controller syntax).</p><p>As a result, you’re shipping super-efficient code much closer to the response pipe. And when AOT gets here, it’ll benefit from runtime performance and treeshaking capabilities. Stay tuned: there’s a lot to wrap your head around here, with more information to come.</p><h2 id="check-out-the-themes-of-net-6">Check out the “themes” of .NET 6</h2><p>It’s a fun time in the .NET 6 release cycle—there’s a lot of design and high-level discussions going on, as it’ll be 11 months before it actually ships. You can definitely look at things like the <a href="https://github.com/dotnet/core/blob/master/product-roadmap/current.md?ref=daveabrock.com">.NET Product Roadmap</a>, but .NET PM Immo Landwerth has <a href="https://themesof.net/?ref=daveabrock.com">built a <em>Themes of .NET</em> site</a>, which shows off the GitHub themes, epics, and stories slotted for .NET 6. (As if you had to ask, yes, <a href="https://github.com/terrajobst/themesof.net?ref=daveabrock.com">it’s built with Blazor</a>.)</p><p>As <a href="https://twitter.com/terrajobst/status/1331821633787424769?ref=daveabrock.com">Immo warns</a>, this is all fluid and not a committed roadmap—it <em>will</em> change frequently as the team’s thinking evolves. Even at this stage, I thought it was interesting to filter by the Priority 0 issues. These aren’t guarantees to make it in, but it <em>is</em> what the team currently is prioritizing the highest.</p><p>📲 With Xamarin coming to .NET 6 <a href="https://devblogs.microsoft.com/dotnet/introducing-net-multi-platform-app-ui/?ref=daveabrock.com">via MAUI</a>, there’s predictably <a href="https://github.com/dotnet/xamarin/issues/2?ref=daveabrock.com">a lot of Priority 0 work</a> outlined here—from <a href="https://github.com/dotnet/xamarin/issues/4?ref=daveabrock.com">managing mobile .NET SDKs</a>, <a href="https://github.com/dotnet/xamarin/issues/10?ref=daveabrock.com">improving performance</a>, and <a href="https://github.com/dotnet/xamarin/issues/16?ref=daveabrock.com">using .NET 6 targets</a>.</p><p>🏫 I’m happy to see an epic around appealing to new developers and students, and there are epics around <a href="https://github.com/dotnet/core/issues/5466?ref=daveabrock.com">teaching entire classes in .NET Notebooks in VS Code</a> and <a href="https://github.com/dotnet/core/issues/5467?ref=daveabrock.com">making setup easier</a>. They’re also prioritizing democratizing machine learning with stories for <a href="https://github.com/dotnet/machinelearning-modelbuilder/issues/556?ref=daveabrock.com">using data when training in the cloud</a> and <a href="https://github.com/dotnet/machinelearning-modelbuilder/issues/642?ref=daveabrock.com">better data loading options</a>.</p><p>🌎 Blazor developers are anxious for <a href="https://github.com/dotnet/runtimelab/issues/248?ref=daveabrock.com">enabling ahead-of-time (AOT) compilation</a>, with stories around <a href="https://github.com/dotnet/runtime/issues/44316?ref=daveabrock.com">compiling .NET apps into WASM</a> and <a href="https://github.com/dotnet/runtime/issues/43390?ref=daveabrock.com">AOT targeting</a>.</p><p>✅ Acknowledging carryover from .NET 5 promises, there are stories for <a href="https://github.com/dotnet/runtime/issues/43546?ref=daveabrock.com">building libraries for HTTP/3</a> and <em>confidently</em> <a href="https://github.com/dotnet/runtime/issues/43540?ref=daveabrock.com">generating single file apps for supported target platforms</a>. There’s also <a href="https://github.com/dotnet/runtime/issues/43543?ref=daveabrock.com">more on app trimming</a> planned, especially <a href="https://github.com/dotnet/runtime/issues/1568?ref=daveabrock.com">when using <code>System.Text.Json</code></a>.</p><p>📈 As promised, a lot to improve the inner-loop performance—plans for the <a href="https://github.com/dotnet/runtime/issues/45023?ref=daveabrock.com">BCL to support hot reloading</a> (and <a href="https://github.com/dotnet/aspnetcore/issues/5456?ref=daveabrock.com">for Blazor</a> to support it), <a href="https://github.com/dotnet/msbuild/issues/5876?ref=daveabrock.com">improving MSBuild performance</a>, and <a href="https://github.com/dotnet/xamarin/issues/13?ref=daveabrock.com">an improved experience for Xamarin devs</a>.</p><p>There’s so much to look through if you’ve got the time, and things are going to move around a lot—there’s a ton of XL-sized Priority 0 issues, for example—but it’s always nice to geek out.</p><h2 id="microsoft-qa-for-net-not-the-overflow-you-re-looking-for">Microsoft Q&amp;A for .NET: Not the Overflow you’re looking for</h2><p>This week, Microsoft <a href="https://devblogs.microsoft.com/dotnet/announcing-microsoft-q-and-a-for-dotnet/?ref=daveabrock.com">announced</a> Microsoft Q&amp;A for .NET. The Q&amp;A experience, a replacement for Microsoft’s older forum platforms like MSDN and TechNet, was <a href="https://docs.microsoft.com/teamblog/introducing-microsoft-qanda?ref=daveabrock.com">first rolled out last October</a> (and <a href="https://docs.microsoft.com/teamblog/microsoft-qna-ga?WT.mc_id=launchblog-blog-learn-tv&ref=daveabrock.com">went GA in May 2020</a>). The inevitable question: “Why not just use and/or buy Stack Overflow?” I find it interesting that this week’s post didn’t mention what every developer was thinking, but I’ve explored <a href="https://docs.microsoft.com/answers/articles/388/microsoft-qa-frequently-asked-questions.html?ref=daveabrock.com">Microsoft’s thoughts from last year</a>:</p><blockquote>We love Stack Overflow. We will continue supporting our customers who ask questions there. In the future, we will introduce a feature that points askers on Microsoft Q&amp;A to relevant answers from Stack Overflow … However, Stack Overflow has specific criteria about what questions are appropriate for the community and Microsoft Q&amp;A will have a more open policy regarding this. More importantly, via Microsoft Q&amp;A we can create unique experiences that allow us to provide the highest level of support for our customers.</blockquote><p>In Microsoft’s defense, <a href="https://docs.microsoft.com/answers/questions/773/why-not-just-use-stack-overflow.html?ref=daveabrock.com">the line</a> “I see too many questions on SO that I believe are viable in any normal support scenario, but get closed and downvoted because people didn’t follow the rules” is all too familiar. There’s a lot of value in a Microsoft-focused platform centered around answers, not reputation.</p><p>In addition, Microsoft is looking to own the experience with additional support channels, badges, and integration with other Microsoft services. I don’t think Stack Overflow is getting nervous—the Q&amp;A UX is similar to the MSDN forums, and that’s not a compliment—but the platform is there if you want to try it. I’ll be curious to see how it evolves.</p><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Andrew Lock <a href="https://andrewlock.net/aspnetcore-in-action-2e-applying-the-mvc-design-pattern-to-razor-pages/?ref=daveabrock.com">applies the MVC design pattern to Razor Pages</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2020/11/25/getting-started-with-entity-framework-core-5/?ref=daveabrock.com">introduces Entity Framework Core 5</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2020/Nov/25/Watch-out-for-NET-Core-Runtime-Bitness-for-IIS-Installs?ref=daveabrock.com">warns against .NET Core runtime bitness for IIS installs when upgrading to .NET 5</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>Jayme Singleton <a href="https://devblogs.microsoft.com/dotnet/dotnetconf-2020-recap?ref=daveabrock.com">wraps up .NET Conf 2020</a>.</li><li>James Montemagno <a href="https://devblogs.microsoft.com/dotnet/announcing-microsoft-q-and-a-for-dotnet/?ref=daveabrock.com">announces Microsoft Q&amp;A for .NET</a>.</li><li>Maoni Stephens <a href="https://devblogs.microsoft.com/dotnet/the-updated-getgcmemoryinfo-api-in-net-5-0-and-how-it-can-help-you/?ref=daveabrock.com">writes about the new GetGCMemoryInfo API in .NET 5</a>.</li><li>Klaus Loeffelmann <a href="https://devblogs.microsoft.com/dotnet/visual-basic-winforms-apps-in-net-5-and-visual-studio-16-8/?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">writes about VB WinForms apps in .NET 5 and Visual Studio 16.8</a>.</li><li>Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-november-2020-cumulative-update-preview?ref=daveabrock.com">provides a .NET Framework November 2020 update</a>.</li><li>Azure Pipelines <a href="https://devblogs.microsoft.com/devops/replacing-view-yaml?ref=daveabrock.com">is replacing the “View YAML” experience</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><p>A light week because of the US Thanksgiving Holiday, so just one community standup—for ASP.NET, <a href="https://www.youtube.com/watch?v=d9Bjg31VuHw&ref=daveabrock.com">David Fowler joins to talk about ASP.NET Core architecture</a>.</p><h3 id="-asp-net-core-blazor">😎 ASP.NET Core / Blazor</h3><ul><li>Dave Brock <a href="https://daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies?ref=daveabrock.com">isolates and test service dependencies in Blazor</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/inline-images-with-asp-net-core?ref=daveabrock.com">works with inline images in ASP.NET Core</a> and also pitfalls of <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-dependency-injection-lifetime-validation?WT.mc_id=DOP-MVP-4025064&ref=daveabrock.com">DI lifetime validation in ASP.NET Core</a>.</li><li>Shaun C. Curtis <a href="https://www.codeproject.com/Articles/5287009/Blazor-WASM-and-Server-in-a-Single-Project-running?ref=daveabrock.com">runs Blazor WASM and Server in a single project on a single site</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/blazor-javascript-isolation-modules-and-dynamic-csharp?ref=daveabrock.com">writes about JS isolation, modules, and dynamic C# with Blazor</a>.</li><li>Jason Farrell <a href="https://jfarrell.net/2020/11/23/using-scoped-dependencies/?ref=daveabrock.com">uses scoped dependencies in ASP.NET Core</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/614/improving-your-aspnet-core-sites-e-mailing-capabilities?ref=daveabrock.com">improves his ASP.NET Core site’s e-mail capabilities</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/css-isolation-in-blazor-applications/?ref=daveabrock.com">writes about Blazor CSS isolation</a> and also <a href="https://code-maze.com/custom-validation-in-blazor-webassembly/?ref=daveabrock.com">works with custom validation in Blazor WebAssembly</a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/generate-client-for-asp-net-core-web-api-using-openapi?ref=daveabrock.com">generates a client for ASP.NET Core Web API using OpenAPI</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/asp-net-core-web-api/four-useful-tips-using-asp-net-core-testserver-in-xunit?ref=daveabrock.com">writes about four useful tips when using the xUnit Test Server in ASP.NET Core</a>.</li></ul><h3 id="-net-5">🚀 .NET 5</h3><ul><li>Alex Yakunin <a href="https://medium.com/swlh/astonishing-performance-of-net-5-more-data-5cdc8d821e8c?ref=daveabrock.com">provides more updates on his performance improvements working with .NET 5</a>.</li><li>Rick Strahl <a href="https://weblog.west-wind.com/posts/2020/Nov/24/Upgrading-to-NET-Core-50?ref=daveabrock.com">upgrades his apps and libraries to .NET 5</a>.</li><li>Davide Benvegnù <a href="https://dev.to/n3wt0n/net-5-is-perfect-for-devops-4afd?ref=daveabrock.com">talks about why .NET 5 is perfect for DevOps</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/how-to-make-a-winforms-app-with-net-5-entirely-from-the-command-line-and-publish-as-one-selfcontained-file?ref=daveabrock.com">makes a self-contained WinForms app with .NET 5 from the command-line</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Dave Brock uses <a href="https://daveabrock.com/2020/11/25/assets/img-azure-blobs-cosmos?ref=daveabrock.com">Azure Functions, Azure Storage blobs, and Cosmos DB to copy images from public URLs</a>.</li><li>Adrian Hall <a href="https://devblogs.microsoft.com/xamarin/azure-mobile-apps-updates?ref=daveabrock.com">announces Azure Mobile Apps v4.2.0 for .NET</a>.</li><li>Tim Sander <a href="https://devblogs.microsoft.com/cosmosdb/difference-between-null-and-undefined?ref=daveabrock.com">writes about the difference between null and undefined in Azure Cosmos DB</a>.</li><li>Mark Heath <a href="https://markheath.net/post/durable-entities-what-are-they-good-for?ref=daveabrock.com">writes about Azure Durable Entities</a>.</li><li>AWS had an outage, <a href="https://aws.amazon.com/message/11201/?ref=daveabrock.com">and an interesting writeup about it</a>.</li></ul><h3 id="-languages">📔 Languages</h3><ul><li>Gergely Sinka <a href="https://developer.okta.com/blog/2020/11/25/how-to-install-dotnetcore-on-linux?ref=daveabrock.com">installs .NET Core apps on Linux in 5 minutes</a>.</li><li>Thomas Levesque <a href="https://thomaslevesque.com/2020/11/23/csharp-9-records-as-strongly-typed-ids-part-2-aspnet-core-route-and-query-parameters/?ref=daveabrock.com">continues writing about C# 9 records as strongly-typed IDs</a>.</li><li>Johnson Manohar <a href="https://www.syncfusion.com/blogs/post/export-excel-files-to-json-using-c-sharp.aspx?ref=daveabrock.com">writes about 4 steps to export Excel files to JSON using C#</a>.</li><li>Vladimir Khorikov <a href="https://enterprisecraftsmanship.com/posts/csharp-records-value-objects/?ref=daveabrock.com">uses C# 9 records as DDD value objects</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/consuming-soap-apis-in-dotnet-core?ref=daveabrock.com">consumes SOAP APIs in .NET Core</a>.</li><li>Prashant Pathak <a href="https://www.compositional-it.com/news-blog/slicing-in-f-and-how-its-a-bit-better-in-f-5?ref=daveabrock.com">slices in F# and writes about how it’s different in F# 5</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Scott Hanselman <a href="https://www.hanselman.com/blog/spectreconsole-lets-you-make-beautiful-console-apps-with-net-core?ref=daveabrock.com">shows off the Spectre.Console project</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/asp-net-core-web-api/asp-net-core-testserver-xunit-test-web-api-endpoints?ref=daveabrock.com">uses ASP.NET Core’s TestServer in xUnit</a>.</li><li>Matt Ward <a href="https://lastexitcode.com/blog/2020/11/21/NuGetSupportInVisualStudioMac8-8/?ref=daveabrock.com">writes about NuGet support in Visual Studio for Mac 8.8</a>.</li><li>Jesse Liberty <a href="http://jesseliberty.com/2020/11/22/get-git-part-2/?ref=daveabrock.com">continues his series on Git</a>.</li><li>Nada Rifki <a href="https://www.telerik.com/blogs/9-best-new-2020-browser-features-you-didnt-know?ref=daveabrock.com">writes about 9 new 2020 browser features</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Daniel Hindrikes <a href="https://danielhindrikes.se/index.php/2020/11/26/github-actions-for-tinymvvm/?ref=daveabrock.com">works on GitHub Actions and Cake for TinyMvvm</a>.</li><li>Rendy Del Rosario <a href="https://www.xamboy.com/2020/11/26/background-distance-based-location-updates-on-ios/?ref=daveabrock.com">works with background distance-based location updates on iOS</a>.</li><li>Charlin Agramonte <a href="https://xamgirl.com/simplifying-bindable-properties-with-type-converters-in-xamarin-forms/?ref=daveabrock.com">simplifies bindable properties with type converters in Xamarin Forms</a>.</li><li>Antonio Liccardi <a href="https://www.infoq.com/news/2020/11/xamarin-forms-5-improvements/?ref=daveabrock.com">talks about new features with Xamarin.Forms 5.0</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/exploring-whats-new-xamarin-essentials-1-6?ref=daveabrock.com">writes about what’s new in Xamarin.Essentials 1.6</a>.</li><li>James Montemagno <a href="https://montemagno.com/enabling-c-9-in-xamarin-net-standard-projects/?ref=daveabrock.com">enables C# 9 in Xamarin and .NET Standard projects</a>.</li><li>Delpin Susai Raj <a href="https://xamarinmonkeys.blogspot.com/2020/11/xamarinforms-file-browser.html?ref=daveabrock.com">uses a file browser</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>Shawn Wildermith talks to <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1715&ref=daveabrock.com">the .NET Rocks podcast</a> and <a href="https://herdingcode.com/herding-code-243-shawn-wildermuth-on-his-new-film-hello-world?ref=daveabrock.com">Herding Code</a> about his new <em>Hello World</em> film.</li><li>The Stack Overflow Podcast <a href="https://the-stack-overflow-podcast.simplecast.com/episodes/big-tech-is-getting-cozy-with-computer-science-departments-82K23tP3?ref=daveabrock.com">discusses how Big Tech is getting cozy with CS departments</a>.</li><li>The 6 Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-171-jeremy-sinclair-windows-insider-net-on-arm/?ref=daveabrock.com">talks to Jeremy Sinclair</a>.</li><li>The MS Dev Show <a href="https://msdevshow.com/2020/11/dot-net-5-with-scott-hunter/?ref=daveabrock.com">talks to Scott Hunter about .NET 5</a>.</li><li>Technology and Friends <a href="http://davidgiard.com/2020/11/23/OmkarNaikOnMicrosoftCloudForHealthCare.aspx?ref=daveabrock.com">talks to Omkar Naik on Microsoft Cloud for Health Care</a>.</li><li>The Unhandled Exception Podcast <a href="https://unhandledexceptionpodcast.com/posts/0004-petegallagher/?ref=daveabrock.com">talks with Pete Gallagher about teaching kids to code</a>.</li><li>The Work Item podcast <a href="https://theworkitem.com/blog/interview-christos-matskas/?ref=daveabrock.com">talks to Christos Matskas</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use ASP.NET Core route-to-code for simple JSON APIs ]]></title>
        <description><![CDATA[ In this post, we explore how you can use route-to-code instead of controllers, and the benefits and drawbacks. ]]></description>
        <link>https://www.daveabrock.com/2020/12/04/migrate-mvc-to-route-to-code/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe77</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Thu, 03 Dec 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1610986602538-431d65df4385?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGpzb258ZW58MHx8fHwxNjE5ODMzOTE1&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>When you need to write an API in ASP.NET Core, you’ve traditionally been forced to use <a href="https://docs.microsoft.com/aspnet/core/web-api/?view=aspnetcore-5.0&ref=daveabrock.com">ASP.NET Core MVC</a>. While it’s very mature and full-featured, it also runs against the core principles of ASP.NET Core—it’s not lightweight or as efficient as other ASP.NET Core offerings. As a result you’re saddled with using all of a framework, even if you aren’t using a lot of its features. In most cases, you’re doing your logic somewhere else and the execution context (the CRUD actions over HTTP) deserves better.</p><p>This doesn’t even include the pitfalls of using controllers and action methods. The MVC pattern invites you to abuse controllers with dependencies and bloat, as much as we preach to other developers about the importance of thin controllers. Microsoft is very aware. This week, in the ASP.NET Standup, architect David Fowler mentioned Project Houdini—an effort to help make APIs over MVC more lightweight and performant (more on this at the end of this post).</p><p>We now have <a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com">an alternative</a> called “route-to-code.” You can now write ASP.NET Core APIs by connecting routing with your middleware. As a result, your code reads the request, writes the response, and you aren’t reliant on a heavy framework and its advanced configuration. It’s a wonderful pipe-to-pipe experience for simple JSON APIs.</p><p>To be clear—and <a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com#notable-missing-features-compared-to-web-api">Microsoft will be the first to tell you this</a>—it is for basic JSON APIs that don’t need things like model binding, content negotiation, and advanced validation. For those scenarios, ASP.NET Core MVC will always be available to you.</p><p>Luckily for me, I just <a href="https://github.com/daveabrock/HttpReplApi?ref=daveabrock.com">wrote a sample API</a> in MVC to <a href="https://daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis?ref=daveabrock.com">look at the HttpRepl tool</a>. This is a great project to use to convert to route-to-code and show my experiences.</p><p>This post contains the following content.</p><ul><li><a href="#how-does-route-to-code-work">How does route-to-code work?</a></li><li><a href="#a-quick-tour-of-the-route-to-code-mvc-project">A quick tour of the route-to-code MVC project</a></li><li><a href="#migrate-our-apis-from-mvc-to-route-to-code">Migrate our APIs from MVC to route-to-code</a></li><li><a href="#the-path-forward">The path forward</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="how-does-route-to-code-work">How does route-to-code work?</h2><p>In route-to-code, you specify the APIs in your project’s <code>Startup.cs</code> file. In this file (<a href="https://docs.microsoft.com/aspnet/core/web-api/route-to-code?view=aspnetcore-5.0&ref=daveabrock.com#api-project-structure">or even in another one</a>), you define the routing and API logic in an application request’s pipeline in <a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.builder.endpointroutingapplicationbuilderextensions.useendpoints?view=aspnetcore-5.0&ref=daveabrock.com">UseEndpoints</a>.</p><p>To use this, ASP.NET Core gives you three helper methods to use:</p><ul><li><a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequestjsonextensions.readfromjsonasync?ref=daveabrock.com">ReadFromJsonAsync</a> - reads JSON from the request and deserializes it to a given type</li><li><a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequestjsonextensions.readfromjsonasync?ref=daveabrock.com">WriteAsJsonAsync</a> - writes a value as JSON to the response body (and also sets the response type to <code>application/json</code>).</li><li><a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequestjsonextensions.hasjsoncontenttype?ref=daveabrock.com">HasJsonContentType</a> - a boolean method that checks the <code>Content-Type</code> header for JSON</li></ul><p>Because route-to-code is for basic APIs only, it does not currently support:</p><ul><li>Model binding or validation</li><li>OpenAPI (Swagger UI)</li><li>Constructor dependency injection</li><li>Content negotiation</li></ul><p>There are ways to work around this, as we’ll see, but if you find yourself writing a lot of repetitive code, it’s a good sign that you might be better off leveraging ASP.NET Core MVC.</p><h2 id="a-quick-tour-of-the-route-to-code-mvc-project">A quick tour of the route-to-code MVC project</h2><p>I’ve got the route-to-code project <a href="https://github.com/daveabrock/RouteToCodePost?ref=daveabrock.com">out on GitHub</a>. I won’t go through all the setup code but will just link to the key parts if you care to explore further.</p><p>In the sample app, I’ve wired up an in-memory Entity Framework database. I’m using <a href="https://github.com/daveabrock/RouteToCodePost/blob/master/Data/SampleContext.cs?ref=daveabrock.com">a <code>SampleContext</code> class</a> that uses Entity Framework Core’s <code>DbContext</code>. I’ve got <a href="https://github.com/daveabrock/RouteToCodePost/blob/master/Data/SeedData.cs?ref=daveabrock.com">a <code>SeedData</code> class</a> that populates the database with <a href="https://github.com/daveabrock/RouteToCodePost/blob/master/Data/ApiModels.cs?ref=daveabrock.com">a model</a> using C# 9 records.</p><p>In the <a href="https://github.com/daveabrock/RouteToCodePost/blob/master/Startup.cs?ref=daveabrock.com"><code>ConfigureServices</code> middleware in <code>Startup.cs</code></a>, I add the in-memory database to the container, then <a href="https://github.com/daveabrock/RouteToCodePost/blob/master/Program.cs?ref=daveabrock.com">flip on the switch in <code>Program.cs</code></a>.</p><h2 id="migrate-our-apis-from-mvc-to-route-to-code">Migrate our APIs from MVC to route-to-code</h2><p>In this post, I’ll look at the GET, GET (by id), POST, and DELETE methods in my MVC controller and see what it takes to migrate them to route-to-code.</p><p>Before we do that, a quick note. In MVC, I’m using constructor injection to access my data from my <code>SampleContext</code>. Because <code>context</code> is a common term in route-to-code, I’ll be naming it <code>repository</code> in route-to-code.</p><p>Anyway, here’s how the constructor injection looks in the ASP.NET Core MVC project:</p><pre><code class="language-csharp">using HttpReplApi.Data;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HttpReplApi.ApiModels;

namespace HttpReplApi.Controllers
{
    [Produces("application/json")]
    [Route("[controller]")]
    public class BandsController : ControllerBase
    {
        private readonly SampleContext _context;

        public BandsController(SampleContext context)
        {
            _context = context;
        }

        // action methods

    }
}
</code></pre><p>In the following sections, I’ll go through all the endpoints and see what it takes to move to route-to-code.</p><h3 id="the-get-all-items-endpoint">The “get all items” endpoint</h3><p>For a “get all” endpoint, the MVC action method is pretty self-explanatory. Since I’ve injected the context and the data is ready for me to query, I just need to get it.</p><pre><code class="language-csharp">[HttpGet]
public ActionResult&lt;IEnumerable&lt;Band&gt;&gt; Get() =&gt;
    _context.Bands.ToList();
</code></pre><p>As mentioned earlier, all the endpoint routing and logic in route-to-code will be inside of <code>app.UseEndpoints</code>:</p><pre><code class="language-csharp">app.UseEndpoints(endpoints =&gt;
{
    // endpoints here
};
</code></pre><p>Now, we can write a <code>MapGet</code> call to define and configure our endpoint. Take a look at this code and we’ll discuss after.</p><pre><code class="language-csharp">endpoints.MapGet("/bands", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();
    var bands = await repository.Bands.ToListAsync();
    await context.Response.WriteAsJsonAsync(bands);
});
</code></pre><p>I’m requesting an HTTP GET endpoint with the <code>/bands</code> route template. In this case, the <code>context</code> is <code>HttpContext</code>, where I can request services, get query strings, and read and write JSON.</p><p>I can’t use constructor-based dependency injection (DI) using route-to-code. Because there’s no framework to inject services into, we need to manually resolve these services. So, from <code>HttpContext.RequestServices</code>, I can call <code>GetService</code> to resolve my <code>SampleContext</code>. For any services with a transient or scoped lifetime, you need to use the <code>RequestServices</code>. For services with singleton scopes, like loggers, you can declare it from the service provider. In those cases, you can use those across different requests. But in our case, we’ll need to repeat the <code>repository</code> service discovery for every endpoint, which is a drag.</p><p>Finally, I’ll send back the <code>Bands</code> collection as JSON using the <code>Response.WriteAsJsonAsync</code> method.</p><h3 id="the-get-by-id-endpoint">The “get by id” endpoint</h3><p>What about the most common use case—getting an item by <code>id</code>? Here’s how we do it in an MVC controller:</p><pre><code class="language-csharp">[HttpGet("{id}")]
public async Task&lt;ActionResult&lt;Band&gt;&gt; GetById(int id)
{
    var band = await _context.Bands.FindAsync(id);

    if (band is null)
    {
        return NotFound();
    }

    return band;
}
</code></pre><p>In route-to-code, here’s how it looks:</p><pre><code class="language-csharp">endpoints.MapGet("/bands/{id}", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();
    var id = context.Request.RouteValues["id"];
    var band = await repository.Bands.FindAsync(Convert.ToInt32(id));

    if (band is null)
    {
        context.Response.StatusCode = StatusCodes.Status404NotFound;
        return;
    }
    await context.Response.WriteAsJsonAsync(band);
});
</code></pre><p>The route matches a passed in <code>id</code> from the route. I need to fetch it by accessing it in <code>Request.RouteValues</code>. One note that isn’t in the documentation: because there’s no model binding, I need to manually convert the <code>id</code> string to an integer. After I figured that out, I was able to call <code>FindAsync</code> from my context, validate it, then write it in the <code>WriteAsJsonAsync</code> method.</p><h3 id="the-post-endpoint">The post endpoint</h3><p>Here’s where things can get interesting—how can we post without model binding or validation?</p><p>Here’s how the existing controller works in ASP.NET Core MVC.</p><pre><code>[HttpPost]
public async Task&lt;ActionResult&lt;Band&gt;&gt; Create(Band band)
{
    _context.Bands.Add(band);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetById), new { id = band.Id }, band);
}
</code></pre><p>In route-to-code, here’s what I wrote:</p><pre><code class="language-csharp">endpoints.MapPost("/bands", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();

    if (!context.Request.HasJsonContentType())
    {
        context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
        return;
    }

    var band = await context.Request.ReadFromJsonAsync&lt;Band&gt;();
    await repository.SaveChangesAsync();
    await context.Response.WriteAsJsonAsync(band);
});
</code></pre><p>As we saw earlier, we have a <code>HasJsonContentType</code> method at our disposal to see if I’m getting JSON. If not, I can set the appropriate status code and return.</p><p>Since I have JSON (no validation or binding, just verification that it <em>is</em> JSON), I can read it in and save it to the database. Once I’m done, I can either <code>WriteAsJsonAsync</code> to give the caller back the new record, or do something like this:</p><pre><code class="language-csharp">context.Response.StatusCode = StatusCodes.Status201Created;
return;
</code></pre><p>The <code>WriteAsJsonAsync</code> will return a 200, and only a 200. Remember, this needs to be done by hand because we don’t have a framework.</p><h3 id="the-delete-endpoint">The delete endpoint</h3><p>For our DELETE API, we’ll see it’s quite similar to POST (we’re just doing the opposite action).</p><p>Here’s what we do in the traditional MVC controller:</p><pre><code class="language-csharp">[HttpDelete("{id}")]
public async Task&lt;IActionResult&gt; Delete(int id)
{
    var band = await _context.Bands.FindAsync(id);

    if (band is null)
    {
        return NotFound();
    }

    _context.Bands.Remove(band);
    await _context.SaveChangesAsync();

    return NoContent();
}
</code></pre><p>Here’s what I wrote in the route-to-code endpoint.</p><pre><code class="language-csharp">endpoints.MapDelete("/bands/{id}", async context =&gt;
{
    var repository = context.RequestServices.GetService&lt;SampleContext&gt;();

    var id = context.Request.RouteValues["id"];
    var band = await repository.Bands.FindAsync(Convert.ToInt32(id));

    if (band is null)
    {
        context.Response.StatusCode = StatusCodes.Status404NotFound;
        return;
    }

    repository.Bands.Remove(band);
    await repository.SaveChangesAsync();
    context.Response.StatusCode = StatusCodes.Status204NoContent;
    return;
});
</code></pre><p>As you can see, there’s a lot of considerations to make even for ridiculously simple APIs like this one. It’s tough to work around dependency injection if you rely on it in your application.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I wish the <a href="https://twitter.com/aspnet?ref_src=twsrc%5Etfw&ref=daveabrock.com">@aspnet</a> core Map methods supported DI enabled requestDelegates 🥺<br><br>Instead I have to program like a caveman <a href="https://t.co/JtjSrkF6yI?ref=daveabrock.com">pic.twitter.com/JtjSrkF6yI</a></p>&mdash; Khalid The Fungi 🍄 (@buhakmeh) <a href="https://twitter.com/buhakmeh/status/1334576089755213828?ref_src=twsrc%5Etfw&ref=daveabrock.com">December 3, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>That’s the price you pay for using a no-framework solution like this one. In return you get simplicity and performance. It’s up to you to decide if you need all the bells and whistles or if you only need route-to-code.</p><h2 id="the-path-forward">The path forward</h2><p>The use case for this is admittedly small, so here’s a thought: what if I could enjoy these benefits in MVC? That’s the impetus behind “Project Houdini”, which David Fowler discussed in this week’s ASP.NET Standup.</p><figure class="kg-card kg-embed-card"><iframe width="560" height="315" src="https://www.youtube.com/embed/d9Bjg31VuHw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></figure><p>This effort focuses on pushing MVC productivity features to the core of the stack with an eye on performance. Fowler showed off a way to generate these route-to-code APIs for you at compile time using source generation—allowing you to keep writing the traditional MVC code. Of course, when AOT comes with .NET 6, it’ll benefit from performance and treeshaking capabilities.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we discussed the route-to-code API style, and how it can help you write simpler APIs. We looked at how to migrate controller code to route-to-code, and also looked at the path forward.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #27: Giving some 💜 to under-the-radar ASP.NET Core 5 features ]]></title>
        <description><![CDATA[ This week, we look at some under-the-radar ASP.NET Core 5 features, and look around the community. ]]></description>
        <link>https://www.daveabrock.com/2020/11/28/dotnet-stacks-27/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe76</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 27 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-18.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter, The .NET Stacks. It was originally sent to subscribers on November 23, 2020. Subscribe at the bottom of this post to get the content right away!</em></p><p>Happy Monday to you all. With .NET 5 out the door and the holidays approaching, things aren’t as crazy. To that end, I wanted to check in on some ASP.NET Core 5 features that might have flown under the radar—and as always, a busy week with our wonderful .NET community.</p><h2 id="giving-some-to-under-the-radar-asp-net-core-5-features">Giving some 💜 to under-the-radar ASP.NET Core 5 features</h2><p>As you may have heard, <a href="https://devblogs.microsoft.com/dotnet/announcing-net-5-0/?ref=daveabrock.com">.NET 5 is officially here</a>. Last week, <a href="https://daveabrock.com/2020/11/21/dotnet-stacks-26?ref=daveabrock.com">we geeked out with .NET Conf</a>. For .NET web developers, Microsoft is pushing Blazor on you <em>hard</em>. And for good reason: it’s the future of ASP.NET and a game-changer in many ways. Bringing C# to the browser is a big deal.</p><p>As a result, Blazor is getting a great deal of the ASP.NET Core 5 attention. It’s important to note that there are still tons of ASP.NET Core developers that aren’t moving to Blazor for a variety of reasons. To be clear, I’m not saying that Microsoft is neglecting these developers—they are not. Also, since Blazor resides in the ASP.NET Core ecosystem, many Blazor-related enhancements help ASP.NET Core as a whole!</p><p>However, with all the attention paid to Blazor, a lot of other ASP.NET Core 5 enhancements may have flown under your radar. So this week, I’d like to spend some time this week focusing on non-Blazor ASP.NET Core 5 improvements.</p><p>(Also, while it’s very much in flight, the .NET team <a href="https://github.com/dotnet/aspnetcore/issues/27883?ref=daveabrock.com">released the initial ASP.NET Core 6 roadmap</a> for your review.)</p><h3 id="-azure-app-service-supports-latest-net-version-automatically">⛅ Azure app service supports latest .NET version automatically</h3><p>You may have noticed that Azure App Service supported .NET 5 on Day 1—meaning when you eagerly downloaded the SDK, you were able to deploy your web apps to Azure App Service. This is thanks to an Early Runtime Feature, which now allows for automatic support of subsequent .NET releases as soon as they’re released. You no longer have to patiently wait for latest-version support.</p><p>Before diving in, though, <a href="https://aka.ms/app-service-early-access?ref=daveabrock.com">get familiar with how it all works</a>.</p><h3 id="-model-binding-works-with-c-9-record-types">🆕 Model binding works with C# 9 record types</h3><p>With <a href="https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records?ref=daveabrock.com">records</a>, immutability is making a big imprint in the C# ecosystem. This can allow you to greatly simplify your need for “data classes”—a big use case is with models that contain properties and no behavior.</p><p>ASP.NET Core 5 now <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#model-binding-and-validation-with-c-9-record-types">can be used for model binding in MVC controllers or Razor Pages</a>. I <a href="https://daveabrock.com/2020/11/18/simplify-api-models-with-records?ref=daveabrock.com">wrote about it last week</a>. Look at how much simpler I can make things.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/api-models.png" class="kg-image" alt="Our title bar in action" loading="lazy" width="889" height="213" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/api-models.png 600w, https://www.daveabrock.com/content/images/2021/05/api-models.png 889w" sizes="(min-width: 720px) 720px"></figure><h3 id="-api-improvements">✅ API improvements</h3><p>I did discuss this a few weeks ago—and <a href="https://daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis?ref=daveabrock.com">also wrote about it last week</a>—but when you create a Web API project in ASP.NET Core 5 (either from Visual Studio or the <code>dotnet</code> CLI), <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#web-api">OpenAPI is enabled by default</a>. This includes adding the Swashbuckle package into your middleware automatically, which allows you to use Swagger UI out-of-the-box. In Visual Studio, just <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#web-api">hit F5 to explore your APIs</a>.</p><p>Also, the <code>FromBody</code> attribute <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#custom-handling-of-authorization-failures">now supports options for optional properties</a>, and <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#custom-handling-of-authorization-failures">new JSON extension methods</a> can help you write lightweight APIs.</p><h3 id="-http-2-and-grpc-performance-improvements">🚀 HTTP/2 and gRPC performance improvements</h3><p>In .NET 5, gRPC has been given the first-class treatment. If you <a href="https://docs.microsoft.com/aspnet/core/grpc/?view=aspnetcore-5.0&ref=daveabrock.com">aren’t familiar</a>, gRPC is a contract-first, open-source remote procedure call (RPC) framework that enables real-time streaming and end-to-end code generation—and leaves a small network footprint with its binary serialization.</p><p>With .NET 5, gRPC gets the <a href="https://devblogs.microsoft.com/aspnet/grpc-performance-improvements-in-net-5/?ref=daveabrock.com">highest requests per second after Rust</a>. This is thanks to <a href="https://devblogs.microsoft.com/aspnet/grpc-performance-improvements-in-net-5/?ref=daveabrock.com#http-2-allocations-in-kestrel">reduced HTTP/2 in Kestrel</a>, improvements <a href="https://devblogs.microsoft.com/aspnet/grpc-performance-improvements-in-net-5/?ref=daveabrock.com#http-2-allocations-in-kestrel">with reading HTTP headers</a>, and support for <a href="https://devblogs.microsoft.com/aspnet/grpc-performance-improvements-in-net-5/?ref=daveabrock.com#protobuf-message-serialization">Protobuf message serialization</a>.</p><p>We are anxiously awaiting Azure App Service and IIS support. Keep an eye on <a href="https://github.com/dotnet/AspNetCore/issues/9020?ref=daveabrock.com">this GitHub issue</a> for updates.</p><h3 id="-authn-and-authz-improvements">🔐 AuthN and AuthZ improvements</h3><p>There’s been quite a few improvements with authentication and authorization.</p><p>First, Microsoft has developed a <a href="https://docs.microsoft.com/dotnet/api/microsoft.identity.web?view=azure-dotnet-preview&ref=daveabrock.com">new <code>Microsoft.Identity.Web</code> library</a> that allows you to handle authentication with Azure Active Directory. You can use this to access Azure resources in an easier way, including with Microsoft Graph. This <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#azure-active-directory-authentication-with-microsoftidentityweb">is supported</a> in ASP.NET Core 5.</p><p>Joseph Guadagno has written <a href="https://www.josephguadagno.net/2020/08/29/working-with-microsoft-identity-configure-local-development?ref=daveabrock.com">some nice posts</a> on the topic—and as a long-time subscriber of <em>The .NET Stacks</em>, you can trust his judgment. 😉</p><p>You can also <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#allow-anonymous-access-to-an-endpoint">allow anonymous access to an endpoint</a>, <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#custom-handling-of-authorization-failures">provide custom handling of authorization failures</a>, and <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#custom-handling-of-authorization-failures">access authorization when using endpoint routing</a>.</p><h3 id="-container-performance-enhancements">📦 Container performance enhancements</h3><p>Before .NET 5, when you published a Dockerfile you needed to pull the whole .NET Core SDK <em>and</em> the ASP.NET Core image. Now, the download size for the SDK is greatly reduced and the runtime image download is almost eliminated (only pulling the manifest). You can check out the GitHub issue to see <a href="https://github.com/dotnet/dotnet-docker/issues/1814?ref=daveabrock.com#issuecomment-625294750">improvement numbers for various environments</a>.</p><h2 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h2><h3 id="-the-top-3">🔥 The Top 3</h3><ul><li>Mika Dumont <a href="https://devblogs.microsoft.com/dotnet/whats-new-in-net-productivity?ref=daveabrock.com">provides an update on .NET productivity (Roslyn)</a>.</li><li>The .NET Docs Show <a href="https://www.youtube.com/watch?v=xwh83W2VWlA&ref=daveabrock.com">talks to Irina Scurtu about REST in .NET</a>.</li><li>Abel Wang <a href="https://devblogs.microsoft.com/devops/static-web-app-pr-workflow-for-azure-app-service-using-azure-devops-pt-2-but-what-if-my-code-is-in-github?ref=daveabrock.com">continues writing about pulling off a Static Web App PR workflow for Azure App Service using Azure DevOps</a>.</li></ul><h3 id="-announcements">📢 Announcements</h3><ul><li>GitHub accounts <a href="https://devblogs.microsoft.com/visualstudio/github-accounts-are-now-integrated-into-visual-studio-2019?ref=daveabrock.com">are now integrated into Visual Studio 2019</a>.</li><li>Microsoft has released <a href="https://blogs.windows.com/windowsdeveloper/2020/11/17/announcing-winui-3-preview-3?ref=daveabrock.com">WinUI 3 Preview 3</a>.</li><li>GitHub Desktop <a href="https://github.blog/2020-11-17-introducing-split-diffs-in-github-desktop/?ref=daveabrock.com">now has split diffs</a>.</li><li>AWS <a href="https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-the-aws-sdk-for-net-version-2/?ref=daveabrock.com">announces end of support for the AWS SDK for .NET version 2</a>.</li><li>Jon Douglas <a href="https://devblogs.microsoft.com/nuget/getting-started-with-nuget-5-8?ref=daveabrock.com">introduces NuGet 5.8</a>.</li><li>Clément Habinshuti <a href="https://devblogs.microsoft.com/odata/introducing-the-odata-web-api-authorization-library?ref=daveabrock.com">introduces the OData Web API authorization library</a>.</li><li>Jimmy Bogard <a href="https://jimmybogard.com/vertical-slice-example-updated-to-net-5?ref=daveabrock.com">updates his vertical slice example to .NET 5</a>.</li></ul><h3 id="-community-and-events">📅 Community and events</h3><ul><li>The Overflow <a href="https://stackoverflow.blog/2020/11/17/the-complexities-and-rewards-of-open-sourcing-corporate-software-products/?ref=daveabrock.com">writes about the complexities and rewards of open sourcing corporate software products</a>.</li><li>For community standups this week, Tooling <a href="https://www.youtube.com/watch?v=XahjibK6SLs&ref=daveabrock.com">talks to Stephen Toub about .NET 5 performance</a>, Entity Framework <a href="https://www.youtube.com/watch?v=AkqRn2vr1lc&ref=daveabrock.com">has an EF Core 5 community panel</a>, and <a href="https://www.youtube.com/watch?v=LjGCPaP8DH8&ref=daveabrock.com">ASP.NET talks about bUnit with Egil Hansen</a>.</li><li>The .NET Foundation <a href="https://dotnetfoundation.org/about/survey?ref=daveabrock.com">wants your feedback</a>, and there might be prizes involved.</li></ul><h3 id="-asp-net-core-blazor">😎 ASP.NET Core / Blazor</h3><ul><li>Dave Brock (hi!) <a href="https://daveabrock.com/2020/11/18/simplify-api-models-with-records?ref=daveabrock.com">simplifies ASP.NET Core API models with C# 9 records</a>, and also <a href="https://daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis?ref=daveabrock.com">works with OpenAPI, Swagger UI, and HttpRepl in ASP.NET Core 5</a>.</li><li>The Code Maze blog <a href="https://code-maze.com/send-sms-aspnetcore/?ref=daveabrock.com">sends an SMS with ASP.NET Core</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/resolve-multiple-types-in-aspnetcore?ref=daveabrock.com">resolves multiple types in ASP.NET Core</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/612/using-standard-health-checks-and-building-your-own-in-aspnet-core?ref=daveabrock.com">uses standard health checks in ASP.NET Core</a>, and also <a href="https://imar.spaanjaars.com/616/unit-testing-authorization-on-your-controllers?ref=daveabrock.com">unit tests authorization on controllers</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/localization-in-blazor-webassembly-applications/?ref=daveabrock.com">writes about localization in Blazor WebAssembly apps</a>, and also <a href="https://code-maze.com/blazor-webassembly-component-virtualization-with-web-api/?ref=daveabrock.com">works with Blazor WebAssembly component virtualization</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/call-anonymous-c-functions-from-js-in-blazor-wasm/?ref=daveabrock.com">calls anonymous C# functions from JS in Blazor WebAssembly</a>.</li><li>Shaun C. Curtis <a href="https://www.codeproject.com/Articles/5286205/An-Alternative-to-Routing-in-Blazor-2?ref=daveabrock.com">offers an alternative to routing in Blazor</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-returning-a-custom-service-provider-from-configureservices?ref=daveabrock.com">discusses pitfalls when returning a custom service provider from ConfigureServices</a>.</li><li>Mark Heath <a href="https://markheath.net/post/openapi-autogen-aspnetcore?ref=daveabrock.com">uses OpenAPI auto-generated clients in ASP.NET Core</a>.</li><li>Roland Weigelt <a href="https://weblogs.asp.net/rweigelt/tiny-difference-big-consequences-reloaded-signalr-in-net-core-3-1-vs-net-5?ref=daveabrock.com">compares SignalR in .NET Core 3.1 vs. .NET 5</a>.</li></ul><h3 id="-the-cloud">⛅ The cloud</h3><ul><li>Damien Bowden <a href="https://damienbod.com/2020/11/20/using-microsoft-graph-api-in-asp-net-core/?ref=daveabrock.com">uses the Microsoft Graph API in ASP.NET Core</a>.</li><li>Azure Tips &amp; Tricks <a href="https://microsoft.github.io/AzureTipsAndTricks/blog/tip295.html?ref=daveabrock.com">writes about which database to use in your next Azure Functions app</a>.</li><li>Mark Heath <a href="https://markheath.net/post/rebus-azure-storage-queues?ref=daveabrock.com">writes about simple messaging with Rebus and Azure Storage queues</a>.</li><li>Joe Guadagno <a href="https://www.josephguadagno.net/2020/11/17/adding-dotnet5-support-to-azure-app-service?ref=daveabrock.com">adds .NET 5 support to Azure App Service</a>.</li><li>Niels Swimberghe <a href="https://swimburger.net/blog/azure/querying-top-requested-urls-using-kusto-and-log-analytics-in-azure-application-insights?ref=daveabrock.com">queries top requested URL’s using Kusto and Log Analytics in Azure Application Insights </a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/publish-asp-net-core-web-api-to-azure-api-management-services?ref=daveabrock.com">publishes an ASP.NET Core Web API to Azure API Management</a>.</li></ul><h3 id="-c-posts">📔 C# posts</h3><ul><li>Konrad Kokosa <a href="https://tooslowexception.com/6-less-popular-facts-about-c-9-records/?ref=daveabrock.com">writes about 6 less popular facts about C# 9 records</a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/recursive-fibonacci-and-memoization-in-csharp?ref=daveabrock.com">writes about recursive Fibonacci and memoization in C#</a>.</li><li>Patrick Smacchia <a href="https://blog.ndepend.com/c-index-and-range-operators-explained/?ref=daveabrock.com">explains C# index and range operators</a>.</li></ul><h3 id="-f-posts">📗 F# posts</h3><ul><li>Timothé Larivière <a href="https://devblogs.microsoft.com/xamarin/fabulous-going-beyond-hello-world?ref=daveabrock.com">writes about Fabulous</a>.</li><li>Alican Demirtas <a href="https://www.compositional-it.com/news-blog/support-for-nameof-in-f-5?ref=daveabrock.com">writes about <code>nameof</code> support in F# 5</a>.</li><li>Angel Munoz writes about <a href="https://dev.to/tunaxor/good-ol-monoliths-1foo?ref=daveabrock.com">monoliths in F# and JS</a>, as well <a href="https://dev.to/tunaxor/looking-at-the-giraffe-18mo?ref=daveabrock.com">as working with Giraffe</a>.</li></ul><h3 id="-tools">🔧 Tools</h3><ul><li>Matt Lacey <a href="https://www.mrlacey.com/2020/11/a-festive-introduction-to-visual-studio.html?ref=daveabrock.com">gets festive with Visual Studio Extensions</a>.</li><li>Derek Comartin <a href="https://codeopinion.com/the-complexity-of-caching?ref=daveabrock.com">talks about the complexity of caching</a>.</li><li>David Walsh <a href="https://davidwalsh.name/git-remove-untracked-files?ref=daveabrock.com">removes untracked files in Git</a>.</li><li>Scott Hanselman <a href="https://www.hanselman.com/blog/your-dotnet-outdated-is-outdated-update-and-help-keep-your-net-projects-up-to-date?ref=daveabrock.com">asks you to update dotnet-outdated because it’s outdated</a>.</li><li>Mark Seemann <a href="https://blog.ploeh.dk/2020/11/16/redirect-legacy-urls/?ref=daveabrock.com">redirects legacy URLs</a>.</li><li>Andrew Lock <a href="https://andrewlock.net/deploying-asp-net-core-applications-to-kubernetes-part-12-tips-tricks-and-edge-cases/?ref=daveabrock.com">offers tips, tricks, and edge cases when deploying to k8s</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2020/11/16/working-with-uno-platform-and-rider/?ref=daveabrock.com">works with Uno Platform and Rider</a>.</li></ul><h3 id="-xamarin">📱 Xamarin</h3><ul><li>Benjamin Askren <a href="https://medium.com/@ben_12456/goodbye-xamarin-forms-f41723fb9fe1?ref=daveabrock.com">says goodbye to Xamarin.Forms</a>.</li><li>Leomaris Reyes <a href="https://askxammy.com/being-friends-with-the-experimental-flags/?ref=daveabrock.com">works with experimental flags</a>.</li></ul><h3 id="-other-finds">🏴‍☠️ Other finds</h3><ul><li>David McCarter <a href="https://www.c-sharpcorner.com/article/the-full-stack-developer-is-a-myth-in-2020/?ref=daveabrock.com">says the “full-stack” developer is a myth</a>.</li><li>The API Evangelist <a href="http://apievangelist.com/2020/11/17/using-api-mocks-as-part-of-an-apifirst-workflow/?ref=daveabrock.com">uses API mocks as part of an API-first workflow</a>.</li></ul><h3 id="-podcasts">🎤 Podcasts</h3><ul><li>The Software Engineering Daily podcast <a href="https://softwareengineeringdaily.com/2020/11/20/graphql-at-github-with-marc-andre-giroux?ref=daveabrock.com">talks about GraphQL at GitHub with Marc-Andre Giroux</a>.</li><li>The .NET Rocks Podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1714&ref=daveabrock.com">talks with Aaron Stannard about Microsoft open source</a>.</li><li>On Software Engineering Radio, <a href="https://www.se-radio.net/2020/11/episode-435-julie-lerman-on-object-relational-mappers-and-entity-framework/?ref=daveabrock.com">Julie Lerman talks about ORMs and EF</a>.</li><li>The Merge Conflict podcast <a href="https://www.mergeconflict.fm/228?ref=daveabrock.com">discusses .NET Conf and the Apple M1 event</a>.</li></ul><h3 id="-videos">🎥 Videos</h3><ul><li>The Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Performance-Profiling--NET-Object-Allocation-Tracking-Tool?ref=daveabrock.com">discusses the .NET object allocation tracking tool</a>.</li><li>Brian Lagunas <a href="https://brianlagunas.com/blazor-cascading-dropdown-not-working-with-inputselect/?ref=daveabrock.com">fixes an issue with Blazor drop-down not working with InputSelect</a>.</li><li>The Azure Enablement series <a href="https://channel9.msdn.com/Shows/Azure-Enablement/Overview-of-Cloud-Adoption-Framework-for-Azure--Introduction-Ep1-Cloud-Adoption-Framework?ref=daveabrock.com">introduces the Cloud Adoption Framework for Azure</a>.</li><li>Jeff Fritz <a href="https://www.youtube.com/watch?v=htB7ohlaYKk&ref=daveabrock.com">talks about new features in C# 9</a>.</li><li>ON.NET talks about <a href="https://www.youtube.com/watch?v=ZsVDgEOoSEU&ref=daveabrock.com">service discovery with Steeltoe</a>, and also <a href="https://www.youtube.com/watch?v=jWIA6vltQuc&ref=daveabrock.com">Steeltoe and Azure Spring Cloud</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use Azure Functions, Azure Storage blobs, and Cosmos DB to copy images from public URLs ]]></title>
        <description><![CDATA[ In this post, we work with Azure Storage blobs and Cosmos DB to copy images that are available over the public Internet. ]]></description>
        <link>https://www.daveabrock.com/2020/11/25/images-azure-blobs-cosmos/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe75</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 24 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1551313158-73d016a829ae?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0b3JhZ2V8ZW58MHx8fHwxNjE5ODM0MDI5&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>There are several reasons why you’ll want to host publicly accessible images yourself. For example, you may want to compress them or apply metadata for querying purposes on your site. For my <em>Blast Off with Blazor</em> project, I had that exact need.</p><p>In my case, I want to host images cheaply and also work with the image’s metadata over a NoSQL database. Azure Storage blobs and Azure Cosmos DB were obvious choices, since I’m already deploying the site as an Azure Static Web App.</p><p>To accomplish this, I wrote a quick Azure Function that accomplishes both tasks. Let’s take a look at how this works.</p><p>(Take a <a href="https://github.com/daveabrock/ImageUploader?ref=daveabrock.com">look at the repository</a> for the full treatment.)</p><h2 id="before-you-begin-create-azure-resources">Before you begin: create Azure resources</h2><p>Before you begin, you need to set up the following:</p><ul><li>An <a href="https://portal.azure.com/?ref=daveabrock.com">Azure storage account</a> (I set up StorageV2, with LRS, and Hot access tier)</li><li>A <a href="https://docs.microsoft.com/azure/storage/blobs/storage-quickstart-blobs-portal?ref=daveabrock.com">blob container</a> to store your images (I set it to public access as anonymous read access is not a concern for publicly available photos)</li><li>A <a href="https://docs.microsoft.com/azure/cosmos-db/create-cosmosdb-resources-portal?ref=daveabrock.com">Cosmos DB resource</a> (I largely accepted the defaults except using the Serverless option, now in preview, to reduce costs)</li><li>A <a href="https://docs.microsoft.com/azure/cosmos-db/create-cosmosdb-resources-portal?ref=daveabrock.com">Cosmos DB collection, database, and container</a></li></ul><p>Once I created all these resources, I added the configuration values to my <code>local.settings.json</code> file. These values are available in the portal when you browse to your various resources. (When you deploy your resources, they’ll need to be added to your configuration.)</p><pre><code class="language-json">{
  "Values": {
    "ApiKey": "my-nasa-api-key",
    "CosmosEndpoint": "url-to-my-cosmos-endpoint",
    "CosmosKey": "my-cosmos-primary-key",
    "CosmosDatabase": "name-of-my-cosmos-db",
    "CosmosContainer": "name-of-my-cosmos-container",
    "StorageAccount": "storage-account-name",
    "StorageKey": "storage-key",
    "BlobContainerUrl": "url-to-my-container"
  }
}
</code></pre><h2 id="the-azure-function">The Azure function</h2><p>In my Azure function I’m doing three things:</p><ul><li>Call the NASA Image of the Day API to get a response with image details—including URL, title, description, and so on</li><li>From the URL in the response payload, copy the image to Azure Storage</li><li>Then, update Cosmos DB with the URL of the new resource, and the other properties in the object</li></ul><p>If we look at the <a href="https://apod.nasa.gov/apod/astropix.html?ref=daveabrock.com">Astronomy Picture of the Day site</a>, it hosts an image and its metadata for the current day. I want to put the image in Storage Blobs and the details in Cosmos DB.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/apod-site.png" class="kg-image" alt="The Astronomy Picture of the Day site" loading="lazy" width="1645" height="1306" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/apod-site.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/apod-site.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/apod-site.png 1600w, https://www.daveabrock.com/content/images/2021/05/apod-site.png 1645w" sizes="(min-width: 720px) 720px"></figure><p>Here’s how the function itself looks:</p><pre><code class="language-csharp">//using System;
//using System.Threading.Tasks;
//using Microsoft.AspNetCore.Mvc;
//using Microsoft.Azure.WebJobs;
//using Microsoft.Azure.WebJobs.Extensions.Http;
//using Microsoft.AspNetCore.Http;
//using Microsoft.Extensions.Logging;
//using Newtonsoft.Json;
//using System.Net.Http;
//using Azure.Storage;
//using Azure.Storage.Blobs;
//using System.Linq;
//using Microsoft.Azure.Cosmos;

public class ImageUploader
{
    private readonly HttpClient httpClient;
    private CosmosClient cosmosClient;

    public ImageUploader()
    {
        httpClient = new HttpClient();
        cosmosClient = new CosmosClient(Environment.GetEnvironmentVariable("CosmosEndpoint"),
                                        Environment.GetEnvironmentVariable("CosmosKey"));
    }

    [FunctionName("Uploader")]
    public async Task&lt;IActionResult&gt; Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "upload")] HttpRequest req, ILogger log)
    {
        var apiKey = Environment.GetEnvironmentVariable("ApiKey");
        var response = await httpClient.GetAsync($"https://api.nasa.gov/planetary/apod?api_key={apiKey}");
        var result = await response.Content.ReadAsStringAsync();

        var imageDetails = JsonConvert.DeserializeObject&lt;Image&gt;(result);

        await UploadImageToAzureStorage(imageDetails.Url);
        await AddImageToContainer(imageDetails);
        return new OkObjectResult("Processing complete.");
    }
}
</code></pre><p>After I get the response back from the API, I deserialize it to an <code>Image</code> model and then do the work in Azure (keep reading for those details).</p><p>Here is the model:</p><pre><code class="language-csharp">using Newtonsoft.Json;
using System;

namespace MassImageUploader
{
    public class Image
    {
        [JsonProperty("id")]
        public Guid Id { get; set; }

        [JsonProperty("title")]
        public string Title { get; set; }

        [JsonProperty("copyright")]
        public string Copyright { get; set; }

        [JsonProperty("date")]
        public DateTime Date { get; set; }

        [JsonProperty("explanation")]
        public string Explanation { get; set; }

        [JsonProperty("url")]
        public string Url { get; set; }
    }
}
</code></pre><h3 id="upload-image-to-azure-storage-blob-container">Upload image to Azure Storage blob container</h3><p>In my <code>UploadImageToAzureStorage</code> method, I pass along the URI of the publicly accessible image. From that, I get the <code>fileName</code> by extracting the last part of the URI (for example, <em>myfile.jpg</em>). With the <code>fileName</code> I build the path of my new resource in the <code>blobUri</code>—that path will include the Azure Storage container URL and the <code>fileName</code>.</p><p>After that, I pass my credentials to a new <code>StorageSharedKeyCredential</code>, and instantiate a new <code>BlobClient</code>. Then, the copy occurs in the <code>StartCopyFromUriAsync</code>, which passes in a URI.</p><pre><code class="language-csharp">private async Task&lt;bool&gt; UploadImageToAzureStorage(string imageUri)
{
    var fileName = GetFileNameFromUrl(imageUri);
    var blobUri = new Uri($"{Environment.GetEnvironmentVariable("BlobContainerUrl")}/{fileName}");
    var storageCredentials = new StorageSharedKeyCredential(
        Environment.GetEnvironmentVariable("StorageAccount"),
        Environment.GetEnvironmentVariable("StorageKey"));
    var blobClient = new BlobClient(blobUri, storageCredentials);
    await blobClient.StartCopyFromUriAsync(new Uri(imageUri));
    return await Task.FromResult(true);
}

private string GetFileNameFromUrl(string urlString)
{
    var url = new Uri(urlString);
    return url.Segments.Last();
}
</code></pre><p>If I browse to my Azure Storage container, I’ll see my new image.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/blob-result.png" class="kg-image" alt="The result" loading="lazy" width="1663" height="1216" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/blob-result.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/blob-result.png 1000w, https://www.daveabrock.com/content/images/size/w1600/2021/05/blob-result.png 1600w, https://www.daveabrock.com/content/images/2021/05/blob-result.png 1663w" sizes="(min-width: 720px) 720px"></figure><h2 id="push-metadata-to-cosmos-db">Push metadata to Cosmos DB</h2><p>With my image successfully stored, I can push the metadata to an Azure Cosmos DB container. In my <code>AddImageToContainer</code> method, I pass in my populated <code>Image</code> model. Then I’ll get the Azure Cosmos DB container, get the path, then call <code>CreateItemAsync</code> while passing in the <code>image</code>. Easy.</p><pre><code class="language-csharp">private async Task&lt;bool&gt; AddImageToContainer(Image image)
{
    var container = cosmosClient.GetContainer(
        Environment.GetEnvironmentVariable("CosmosDatabase"),
        Environment.GetEnvironmentVariable("CosmosContainer"));

    var fileName = GetFileNameFromUrl(image.Url);

    image.Id = Guid.NewGuid();
    image.Url = $"{Environment.GetEnvironmentVariable("BlobContainerUrl")}/{fileName}";

    await container.CreateItemAsync(image);
    return await Task.FromResult(true);
}
</code></pre><p>In the Data Explorer for my Cosmos DB resource in the Azure portal, I can see my new record.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/cosmos-result.png" class="kg-image" alt="The result" loading="lazy" width="1149" height="676" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/cosmos-result.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/cosmos-result.png 1000w, https://www.daveabrock.com/content/images/2021/05/cosmos-result.png 1149w" sizes="(min-width: 720px) 720px"></figure><h2 id="wrap-up">Wrap up</h2><p>In this post, we learned how to store a publicly accessible image in Azure Storage, then post that URL and other metadata in Azure Cosmos DB.</p><p>As always, feel free to post any feedback or experiences in the comments.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Isolate and test your service dependencies ]]></title>
        <description><![CDATA[ In this post, we refactor our component to inject an API service wrapper, to abstract away a direct HttpClient dependency. ]]></description>
        <link>https://www.daveabrock.com/2020/11/22/blast-off-blazor-service-dependencies/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe74</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 21 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDR8fHRlc3R8ZW58MHx8fHwxNjE5ODM0MDU0&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in our series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through the intro</a>, <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">wrote our first component</a>, and <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">dynamically updated the HTML head from a component</a>.</p><p>I’ve made testing a crucial part of this project and not an afterthought—as discussed previously, we’re <a href="https://bunit.egilhansen.com/docs/getting-started/index.html?ref=daveabrock.com">using the bUnit project</a> to unit test our components. As I <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com#what-about-the-tests">discussed last time</a>, though, testing our <code>Index</code> component was a little cumbersome because of the <code>HttpClient</code> dependency. There are ways to <a href="https://bunit.egilhansen.com/docs/test-doubles/mocking-httpclient.html?ref=daveabrock.com">mock and test it</a>, but we should ask … why are we injecting it directly?</p><p>It was great to inject it easily to get up and running but what happens as we build more components and more APIs to call, each with different endpoints and request headers? How will we manage that? And if we want to unit test our components, will I have to mock an <code>HttpClient</code> every time? What a nightmare.</p><p>Instead, we’ll create an API wrapper and inject that in our components. Any service-level implementation details can be abstracted away from the component. Along the way, we’ll learn about working with separate C# classes, using a named <code>IHttpClientFactory</code>, and how to quickly mock and test a service in bUnit. Let’s get started.</p><p>This post contains the following content.</p><ul><li><a href="#does-my-code-always-have-to-reside-in-code-blocks">Does my code always have to reside in @code blocks?</a></li><li><a href="#add-an-api-service-wrapper-to-our-project">Add an API service wrapper to our project</a></li><li><a href="#test-our-component">Test our component</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="does-my-code-always-have-to-reside-in-code-blocks">Does my code always have to reside in @code blocks?</h2><p>To recap, here’s how our main component currently looks.</p><pre><code class="language-html">@page "/"
@inject HttpClient http

@if (image != null)
{
    &lt;div class="p-4"&gt;
        &lt;h1 class="text-6xl"&gt;@image.Title&lt;/h1&gt;
        &lt;p class="text-2xl"&gt;@FormatDate(image.Date)&lt;/p&gt;
        @if (image.Copyright != null)
        {
            &lt;p&gt;Copyright: @image.Copyright&lt;/p&gt;
        }
    &lt;/div&gt;

     &lt;div class="flex justify-center p-4"&gt;
        &lt;img src="@image.Url" class="rounded-lg h-500 w-500 flex items-center justify-center"&gt;&lt;br /&gt;
    &lt;/div&gt;
}

@code {
    private Data.Image image;

    private string FormatDate(DateTime date) =&gt; date.ToLongDateString();

    protected override async Task OnInitializedAsync()
    {
        image = await http.GetFromJsonAsync&lt;Data.Image&gt;("api/image");
    }
}
</code></pre><p>While we don’t have a lot of lines of code in the <code>@code</code> block, there’s still a lot going on in this component. We’re directly injecting <code>HttpClient</code> to directly call our Azure Function. In the <code>@code</code> section I’ve written a helper method as well as <code>OnInitializedAsync</code> behavior. As we add more features and functionality, that <code>@code</code> block is only going to grow. We can definitely keep the C# coupled with our Razor syntax, as it makes it easy to see all that’s going on in one file—but we also can move all of this to a <a href="https://docs.microsoft.com/aspnet/core/blazor/components/?view=aspnetcore-5.0&ref=daveabrock.com#partial-class-support">separate C# file</a> for reuse and maintainability purposes.</p><p>This is a “code-behind” approach, as the code will sit behind the view logic in a partial class. To do this, we’ll create an <code>Index.razor.cs</code> file. If you’re using Visual Studio, you’ll see it’s nested “inside” the Blazor component.</p><p>Cut and paste everything inside the <code>@code</code> block to the new file. You’ll see some build errors and will need to resolve some dependencies. To resolve these:</p><ul><li>Make the new file a <code>partial class</code></li><li>Add a using statement for <code>Microsoft.AspNetCore.Components</code></li><li>With the using added, inherit <code>ComponentBase</code></li></ul><p>What about injecting <code>HttpClient</code>, though? We can’t carry over that Razor syntax to our C# file. Instead, we’ll add it as a property with an <code>Inject</code> annotation above it.</p><p>Here’s how the class looks:</p><pre><code class="language-csharp">using Client.Services;
using Data;
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;

namespace Client.Pages
{
    partial class Index : ComponentBase
    {
        Image _image;

        [Inject]
        public HttpClient http { get; set; }

        private static string FormatDate(DateTime date) =&gt; date.ToLongDateString();

        protected override async Task OnInitializedAsync()
        {
            image = await http.GetFromJsonAsync&lt;Data.Image&gt;("api/image");
        }
    }
}
</code></pre><p>Now, when we remove the <code>@code</code> block and <code>HttpClient</code> injection, our component looks cleaner:</p><pre><code class="language-html">
@page "/"

@if (_image is null)
{
    &lt;p&gt;Loading...&lt;/p&gt;
}
else
{
    &lt;div class="p-4"&gt;
        &lt;h1 class="text-6xl"&gt;@_image.Title&lt;/h1&gt;
        &lt;p class="text-2xl"&gt;@FormatDate(_image.Date)&lt;/p&gt;
        @if (_image.Copyright != null)
        {
            &lt;p&gt;Copyright: @_image.Copyright&lt;/p&gt;
        }
    &lt;/div&gt;

    &lt;div class="flex justify-center p-4"&gt;
        &lt;img src="@_image.Url" class="rounded-lg h-500 w-500 flex items-center justify-center"&gt;&lt;br /&gt;
    &lt;/div&gt;
}
</code></pre><p>If we run the project, it’ll work as it always has. Now, let’s build out an API wrapper.</p><h2 id="add-an-api-service-wrapper-to-our-project">Add an API service wrapper to our project</h2><p>We’re now ready to build our service. In our <code>Client</code> project, create an <code>ApiClientService.cs</code> file inside a <code>Services</code> folder. We’ll stub it out for now with an interface to boot:</p><pre><code class="language-csharp">public interface IApiClientService
{
    public Task&lt;Image&gt; GetImageOfDay();
}

public class ApiClientService : IApiClientService
{
    public async Task&lt;Image&gt; GetImageOfDay()
    {
        throw new NotImplementedException();
    }
}
</code></pre><p>We’ll also want to add the new folder to bottom of our <code>_Imports.razor</code> file:</p><pre><code>@using Services
</code></pre><h3 id="how-to-call-httpclient-from-our-app">How to call HttpClient from our app</h3><p>We could still call <code>HttpClient</code> directly, but over the course of this project we’ll be connecting to various APIs with different endpoints, different headers, and so on. As we look forward, <a href="https://docs.microsoft.com/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0&ref=daveabrock.com#named-clients">we should create an <code>IHttpClientFactory</code></a>. This allows us to work with named instances, allows us to delegate middleware handlers, and manages the lifetime of handler instances for us.</p><p>To add a factory to our project, we’ll add a named client to our <code>Program.cs</code> file. While we’re here, we’ll inject our new <code>IApiClientService</code> as well.</p><pre><code class="language-csharp">public static async Task Main(string[] args)
{
    // important stuff removed for brevity
    builder.Services.AddHttpClient("imageofday", iod =&gt;
    {
        iod.BaseAddress = new Uri(builder.Configuration["API_Prefix"] ?? builder.HostEnvironment.BaseAddress);
    });
    builder.Services.AddScoped&lt;IApiClientService, ApiClientService&gt;();
}
</code></pre><p>In <code>AddHttpClient</code>, I’m specifying a URI, and referencing my API as <code>imageofday</code>. With that in place, I can scoot over to <code>ApiClientService</code> and make it work.</p><p>First, let’s inject our <code>ILogger</code> and <code>IHttpClientFactory</code> in the constructor.</p><pre><code class="language-csharp">public class ApiClientService : IApiClientService
{
    readonly IHttpClientFactory _clientFactory;
    readonly ILogger&lt;ApiClientService&gt; _logger;

    public ApiClientService(ILogger&lt;ApiClientService&gt; logger, IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
        _logger = logger;
    }
}
</code></pre><p>In our <code>GetImageOfDay</code> logic, we’ll create our named client and use it to call to our Azure Function at the <code>api/image</code> endpoint. Of course, we’ll catch any exceptions and log them appropriately.</p><pre><code class="language-csharp">public async Task&lt;Image&gt; GetImageOfDay()
{
    try
    {
        var client = _clientFactory.CreateClient("imageofday");
        var image = await client.GetFromJsonAsync&lt;Image&gt;("api/image");
        return image;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex.Message, ex);
    }

    return null;
}
</code></pre><h3 id="inject-our-new-service-from-our-component">Inject our new service from our component</h3><p>With the service wrapper now complete, we can inject our new service instead of direct dependency on <code>HttpClient</code>. Change the <code>HttpClient</code> injection in <code>Index.razor.cs</code> to our new service instead:</p><pre><code class="language-csharp">[Inject]
public IApiClientService ApiClientService { get; set; }

// stuff

protected override async Task OnInitializedAsync()
{
    _image = await ApiClientService.GetImageOfDay();
}
</code></pre><p>If you run the app, you should see no changes—we didn’t have to modify the markup at all—but we’ve made our lives a lot easier and now testing should be a snap as we add to our project).</p><h2 id="test-our-component">Test our component</h2><p>With our API wrapper in place, testing is a whole lot easier. I’ve created an <code>ImageOfDayTest</code> class in our <code>Test</code> library.</p><p>I’ll be adding a reference to <code>Moq</code>, a popular mocking library, to mimic the response back from our service. You can <a href="https://www.nuget.org/packages/moq/?ref=daveabrock.com">download the package</a> from NuGet Package Manager or just drop this in <code>Test.csproj</code>:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;PackageReference Include="Moq" Version="4.15.1" /&gt;
&lt;/ItemGroup&gt;
</code></pre><p>I’ll build out a sample <code>Image</code> to return from the service. I’ll create a private helper method for that:</p><pre><code class="language-csharp">private static Image GetImage()
{
    return new Image
    {
        Date = new DateTime(2020, 01, 01),
        Title = "My Sample Image",
        Url = "https://nasa.gov"
    };
}
</code></pre><p>In my test case, I’ll mock my client, return an image, and inject it into my bUnit’s <code>TestContext</code>:</p><pre><code class="language-csharp">var mockClient = new Mock&lt;IApiClientService&gt;();
mockClient.Setup(i =&gt; i.GetImageOfDay()).ReturnsAsync(GetImage());

using var ctx = new TestContext();
ctx.Services.AddSingleton(mockClient.Object);
</code></pre><p><em>Note</em>: The integration test vs. mocking in a unit test <a href="https://tyrrrz.me/blog/unit-testing-is-overrated?ref=daveabrock.com">is a hot topic</a>, especially when testing dependencies. My intent here is to unit test rendering behavior and not my services, but calling the endpoint from the test is also an option if you’re up for it.</p><p>With that in place, I can render my component, and assert against expected output with the following code:</p><pre><code class="language-csharp">var cut = ctx.RenderComponent&lt;Client.Pages.Index&gt;();
var h1Element = cut.Find("h1").TextContent;
var imgElement = cut.Find("img");
var pElement = cut.Find("p");

h1Element.MarkupMatches("My Sample Image");
imgElement.MarkupMatches(@"&lt;img src=""https://nasa.gov"" 
    class=""rounded-lg h-500 w-500 flex items-center justify-center""&gt;");
pElement.MarkupMatches(@"&lt;p class=""text-2xl""&gt;Wednesday, January 1, 2020&lt;/p&gt;");
</code></pre><p>My tests pass—ship it!</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we learned how to isolate <code>HttpClient</code> dependencies in our Blazor code. To do this, we moved our component’s C# code to a partial “code-behind class” and built a service that uses the <code>IHttpClientFactory</code>. Then, we were able to use bUnit to test our component quite easily.</p><p>Are refactorings sexy? No. Are they fun? Also no. Are they important? Yes. Is this the last question I’ll ask myself in this post? Also yes. In the next post, we’ll get back to updating the UI.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #26: .NET 5 has arrived, let&#x27;s party ]]></title>
        <description><![CDATA[ This week, we look at the .NET Conf content and also discuss the buzz around dependency injection. ]]></description>
        <link>https://www.daveabrock.com/2020/11/21/dotnet-stacks-26/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe73</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Fri, 20 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-19.png" medium="image"/>
        <content:encoded><![CDATA[ <p><em>Note: This is the published version of my free, weekly newsletter: The .NET Stacks—originally sent to subscribers on November 16, 2020. Subscribe at the bottom of this post to get the content right away!</em></p><p>Happy Monday, everybody! I hope you have a wonderful week. We’ll be covering a few things this morning:</p><ul><li>.NET 5 has arrived</li><li>Dependency injection gets a community review</li><li>Last week in .NET world</li></ul><h1 id="-net-5-has-arrived">🥳.NET 5 has arrived</h1><p>Well, we made it: .NET 5 is <a href="https://devblogs.microsoft.com/dotnet/announcing-net-5-0?ref=daveabrock.com">officially here</a>. This week, Microsoft showed off their hard work during three busy days of .NET Conf—and with it, some <a href="https://www.dotnetconf.net/swag?ref=daveabrock.com">swag</a> including my new <a href="https://marketplace.visualstudio.com/items?itemName=dotnetconfteam.dotnet-purple-theme&ref=daveabrock.com">default Visual Studio Code theme</a>. I’m starting to wonder if overhyping Blazor is possible—as great as it is, I wish Microsoft would dial it back a bit.</p><p>Anyway: we’ve spent the better part of six months discussing all the updates (like, <a href="https://daveabrock.com/2020/11/13/dotnet-stacks-25?ref=daveabrock.com">my favorite things</a>, <a href="https://daveabrock.com/2020/11/06/dotnet-stacks-24?ref=daveabrock.com">Blazor’s readiness</a>, <a href="https://daveabrock.com/2020/10/31/dotnet-stacks-23?ref=daveabrock.com">the support model</a>, <a href="https://daveabrock.com/2020/09/26/dotnet-stacks-18?ref=daveabrock.com">what’s happening to .NET Standard</a>, <a href="https://daveabrock.com/2020/09/19/dotnet-stacks-17?ref=daveabrock.com">EF Core 5</a>, <a href="https://daveabrock.com/2020/09/12/dotnet-stacks-16?ref=daveabrock.com">app trimming</a>, <a href="https://daveabrock.com/2020/08/08/dotnet-stacks-11?ref=daveabrock.com">System.Text.Json vs. Newtonsoft</a>, and so much more).</p><p>I know you’re here for the .NET Conf links—so let me be of service. You can see all the talks <a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oVWop1HEOml2OdqbDs6IlcI&ref=daveabrock.com">from this YouTube playlist</a>, but the highlights are below.</p><p>From the Microsoft perspective, we had the following sessions:</p><ul><li>The Scotts <a href="http://www.youtube.com/watch?v=o-esVzL3YLI&ref=daveabrock.com">welcome you to .NET 5</a>.</li><li>Mads Torgersen and Dustin Campbell <a href="https://www.youtube.com/watch?v=x3kWzPKoRXc&ref=daveabrock.com">talk about C# 9</a>, and Phillip Carter <a href="https://www.youtube.com/watch?v=MPlVE8WdD-0&ref=daveabrock.com">introduces F# 5</a>.</li><li>Immo Landwerth and Phillip Carter <a href="http://www.youtube.com/watch?v=bvmd2F11jpA&ref=daveabrock.com">port projects to .NET 5</a>.</li><li>Jeremy Likness and Shay Rojansky <a href="https://www.youtube.com/watch?v=BIImyq8qaD4&ref=daveabrock.com">talk about Entity Framework Core 5</a>.</li><li>James Newton-King <a href="http://www.youtube.com/watch?v=EJ8M2Em5Zzc&ref=daveabrock.com">discusses high performance with gRPC</a>.</li><li>Steve Sanderson and Safia Abdalla <a href="https://www.youtube.com/watch?v=Nag6u5TxjIA&ref=daveabrock.com">talk about Blazor in .NET 5</a>, and Daniel Roth and Javier Calvarro talk about <a href="https://www.youtube.com/watch?v=CEjqhTGrqDY&ref=daveabrock.com">integrating it with ASP.NET Core</a>.</li><li>Rich Lander, Jan Kotas, and Stephen Toub <a href="https://www.youtube.com/watch?v=qJXJnop1bZ0&ref=daveabrock.com">dive deep on the .NET 5 runtime</a>.</li><li>Scott Hanselman <a href="https://www.youtube.com/watch?v=28D_roo3cUw&ref=daveabrock.com">updates his site to .NET 5, live</a>.</li><li>Chris Sfanos and Dmitry Lyalin <a href="https://www.youtube.com/watch?v=NDYcq1yKhiA&ref=daveabrock.com">provide a .NET desktop development update</a>.</li><li>Claire Novotny and Layla Porter <a href="http://www.youtube.com/watch?v=ppIBnjAdgik&ref=daveabrock.com">provide a .NET Foundation update</a>.</li><li>Maddy Leger and David Ortinau <a href="https://www.youtube.com/watch?v=M7UVz82dE90&ref=daveabrock.com">roll out Xamarin.Forms 5</a>.</li><li>Glenn Condrong and David Fowler <a href="https://www.youtube.com/watch?v=_s8UdhGOGmY&ref=daveabrock.com">talk about microservices with Project Tye</a>.</li><li>Kathleen Dollard and Rainer Sigwald <a href="https://www.youtube.com/watch?v=WmOCtlvNaTQ&ref=daveabrock.com">get to know the .NET 5 SDK</a>.</li><li>Leslie Richardson talks about <a href="https://www.youtube.com/watch?v=cOYFDD3tU38&ref=daveabrock.com">debugging in Visual Studio with Mark Downie</a>.</li><li>Robert Green and Brady Gaster talk about <a href="https://www.youtube.com/watch?v=G7Le65Ln_Qk&ref=daveabrock.com">HTTP API development with .NET, Azure, and OpenAPI</a>.</li><li>Jon Galloway talks with David Wengier <a href="https://www.youtube.com/watch?v=3YwwdoRg2F4&ref=daveabrock.com">about C# source generators</a>.</li><li>Eilon Lipton <a href="https://www.youtube.com/watch?v=qTPHAlHom20&ref=daveabrock.com">shows off Blazor Mobile Bindings</a>.</li></ul><p>From the community:</p><ul><li>Carl Franklin <a href="https://www.youtube.com/watch?v=GIupo55GTro&ref=daveabrock.com">talks about application state in Blazor apps</a>.</li><li>Ed Charbeneau <a href="https://www.youtube.com/watch?v=WdB723tIWg0&ref=daveabrock.com">talks about Blazor stability testing tools</a>.</li><li>Vaibhav Gujral <a href="https://www.youtube.com/watch?v=-hxQNjZfRYg&ref=daveabrock.com">talks about Azure Static Web Apps</a>.</li><li>Veronika Kolesnikova <a href="https://www.youtube.com/watch?v=WKtUkZzi0jc&ref=daveabrock.com">talks about ML.NET, Azure, and Xamarin</a>.</li><li>Menaka Basker <a href="https://www.youtube.com/watch?v=espeHztMDS8&ref=daveabrock.com">architects cloud native apps in Azure with .NET Core</a>.</li><li>Bryan Hogan <a href="https://www.youtube.com/watch?v=L9_fGJOqzbM&ref=daveabrock.com">discusses Polly</a>.</li><li>Lizzy Gallagher <a href="https://www.youtube.com/watch?v=C-2haqb60No&ref=daveabrock.com">discusses .NET Core migration at enterprise scale</a>.</li><li>Nico Paez talks about <a href="https://www.youtube.com/watch?v=mF6qQCW_fOI&ref=daveabrock.com">testing with extension methods and fluent interfaces</a>.</li><li>Zaid Ajaj <a href="https://www.youtube.com/watch?v=a6Ct3CM_lj4&ref=daveabrock.com">builds React applications with F#</a>.</li><li>Eduard Keilholz <a href="https://www.youtube.com/watch?v=PDMRaNoS2Xc&ref=daveabrock.com">gets real-time insights from serverless solutions</a>.</li><li>Luis Beltran <a href="https://www.youtube.com/watch?v=YapSbK75_1w&ref=daveabrock.com">discusses AI enrichment with Azure Cognitive Search</a>.</li><li>Florian Rappl <a href="https://www.youtube.com/watch?v=npff2NjVXEE&ref=daveabrock.com">talks about microfrontends with Blazor</a>.</li></ul><h1 id="-dependency-injection-gets-a-community-review">💉 Dependency injection gets a community review</h1><p>During the day job, I’ve been teaching infrastructure engineers how to code in C#. With plenty of experience with scripting languages like PowerShell, explaining variables, functions, and loops isn’t really a big deal. Next week, however, I’ll have to discuss dependency injection and I’m not looking forward to it. That’s not because they won’t understand it, because they’re very smart and they definitely will (eventually). It’s because it’s a head-spinning topic to beginners but is essential to learn because ASP.NET Core is centered around it.</p><p>If you aren’t familiar with dependency injection, it’s a software design pattern that helps manage dependencies <a href="https://docs.microsoft.com/dotnet/architecture/modern-web-apps-azure/architectural-principles?ref=daveabrock.com#dependency-inversion">towards abstractions and not lower-level implementation details</a>. <a href="https://ardalis.com/new-is-glue/?ref=daveabrock.com">New is glue</a>, after all. In ASP.NET Core, we use interfaces (or base classes) to abstract dependencies away, and “register” dependencies in a service container (most commonly IServiceProvider in the ConfigureServices method in a project’s Startup class). This allows us to “inject” services (or groups of services) only when we need them.</p><p>Right on cue, this week’s edition of .NET Twitter Drama included the <a href="https://twitter.com/davidfowl/status/1326271656776634368?ref=daveabrock.com">discussion</a> of a <a href="https://t.co/Lq0KCy0jKZ?amp=1&ref=daveabrock.com">Hacker News article</a> criticizing the ASP.NET Core DI practice as overkill. The article mirrors a lot of HN: .NET rants with some valuable feedback nested inside.</p><p>In my experience, DI in general is a difficult concept to learn initially but sets you up for success for maintaining loose coupling and testability as your project matures. However, the initial ceremony can drive people away from ASP.NET Core as developers can view it as overkill if they think their project will never need it.</p><p>I do think the conversation this week helped folks understand that working with settings is very ceremonial and can lead to confusion (just look at the options pattern). This might foster .NET team discussions about doc updates and how to provide a better experience when working with configuration. A boy can dream, anyway.</p><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Maybe you’ve heard: .NET 5 is here. Richard Lander <a href="https://devblogs.microsoft.com/dotnet/announcing-net-5-0?ref=daveabrock.com">has the announcement</a>, Daniel Roth <a href="https://devblogs.microsoft.com/aspnet/announcing-asp-net-core-in-net-5?ref=daveabrock.com">discusses ASP.NET Core 5</a>, and Jeremy Likness <a href="https://devblogs.microsoft.com/dotnet/announcing-the-release-of-ef-core-5-0?ref=daveabrock.com">covers EF Core 5</a>.</li><li>From the language side, Mads Torgersen <a href="https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record?ref=daveabrock.com">provides an update on C# 9</a> and Phillip Carter <a href="https://devblogs.microsoft.com/dotnet/announcing-f-5?ref=daveabrock.com">announces F# 5</a>.</li><li>Ed Charbeneau <a href="https://www.telerik.com/blogs/blazor-stability-testing-tools-for-bulletproof-applications?ref=daveabrock.com">writes about Blazor stability testing tools</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>For Visual Studio: Jacqueline Widdis <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-8?ref=daveabrock.com">writes about the Visual Studio 2019 v16.8 and v16.9 Preview 1 releases</a>, Pratik Nadagouda <a href="https://devblogs.microsoft.com/visualstudio/announcing-the-release-of-the-git-experience-in-visual-studio?ref=daveabrock.com">writes about the release of the Git experience in Visual Studio</a>, and Jon Galloway <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-version-8-8-is-now-available?ref=daveabrock.com">rolls out Visual Studio 2019 for Mac version 8.8</a>.</li><li>Peter Groenewegen <a href="https://devblogs.microsoft.com/visualstudio/intellicode-suggestion-apply-all?ref=daveabrock.com">provides an update on IntelliCode suggestions</a>.</li><li>Joey Aiello <a href="https://devblogs.microsoft.com/powershell/announcing-powershell-7-1?ref=daveabrock.com">introduces PowerShell 7.1</a>.</li><li>Angela Zhang <a href="https://blogs.windows.com/windowsdeveloper/2020/11/10/announcing-c-winrt-version-1-0-with-the-net-5-ga-release?ref=daveabrock.com">announces the C#/WinRT Version 1.0 with .NET 5 GA</a>.</li><li>Rahul Bhandari <a href="https://devblogs.microsoft.com/dotnet/net-core-november-2020?ref=daveabrock.com">provides the .NET Core November 2020 updates</a>, and Tara Overfield <a href="https://devblogs.microsoft.com/dotnet/net-framework-november-2020-security-and-quality-rollup-updates?ref=daveabrock.com">discusses the .NET Framework 2020 security updates</a>.</li><li>Filip Woj <a href="https://www.strathweb.com/2020/11/dotnet-script-1-0-0-released-with-support-for-net-5-0-and-c-9/?ref=daveabrock.com">releases dotnet-script 1.0.0</a>.</li><li>Kayla Cinnamon <a href="https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-5-release?ref=daveabrock.com">walks through Windows Terminal Preview 1.5</a>.</li><li>Uno <a href="https://platform.uno/blog/uno-platform-3-2-net-5-c-9-support-and-net-5-webassembly-aot-support/?ref=daveabrock.com">discusses .NET 5 and C# 9 support in Uno Platform 3.2</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><p>With .NET Conf, no community standups so a light section except: The .NET Docs Show <a href="https://www.youtube.com/watch?v=2xeKomASV0E&ref=daveabrock.com">codes a drone with Bruno Capuano</a>.</p><h2 id="-net-5">🚀 .NET 5</h2><ul><li>David Hayden <a href="https://www.davidhayden.me/blog/ef-core-5-many-to-many-relationships?ref=daveabrock.com">writes about EF Core 5 many-to-many relationships</a>, <a href="https://www.davidhayden.me/blog/asp-net-core-5-model-binding-to-csharp-9-record-types?ref=daveabrock.com">ASP.NET Core 5 model binding to C# 9 record types</a>, and <a href="https://www.davidhayden.me/blog/openapi-and-swagger-ui-in-asp-net-core-5-web-api?ref=daveabrock.com">OpenAPI and Swagger UI in ASP.NET Core 5 Web API</a>.</li><li>Michael MacDonald asks: <a href="https://medium.com/young-coder/does-net-5-deliver-8f3f89193d21?ref=daveabrock.com">does .NET 5 deliver</a>?</li><li>Alex Yakunin <a href="https://alexyakunin.medium.com/astonishing-performance-of-net-5-7803d69dae2e?ref=daveabrock.com">talks about his performance gains in .NET 5 when migrating his Fusion project</a>.</li><li>Mitchel Sellers <a href="https://www.mitchelsellers.com/blog/article/net-5-is-here-now-what?ref=daveabrock.com">talks about what to do now that .NET 5 is here</a>.</li><li>Miguel Bernard <a href="https://blog.miguelbernard.com/net-5-the-breaking-changes-you-need-to-know-about/?ref=daveabrock.com">sums up the .NET 5 breaking changes</a>.</li><li>Andrea Chiarelli <a href="https://auth0.com/blog/dotnet-5-whats-new/?ref=daveabrock.com">writes about five things you should know about .NET 5</a>.</li><li>David Grace <a href="https://www.roundthecode.com/dotnet/five-questions-you-may-have-about-asp-net-core-for-dotnet-5?ref=daveabrock.com">answers five questions about .NET 5</a>.</li></ul><h2 id="-asp-net-core-blazor">😎 ASP.NET Core / Blazor</h2><ul><li>Marinko Spasojevic <a href="https://code-maze.com/global-http-error-handling-in-blazor-webassembly/?ref=daveabrock.com">writes about global HTTP error handling in Blazor WebAssembly</a>.</li><li>Jon Hilton asks: <a href="https://jonhilton.net/blazor-dynamic-components/?ref=daveabrock.com">is it possible to render components “dynamically” in Blazor</a>?</li><li>Marinko Spasojevic <a href="https://code-maze.com/lazy-loading-in-blazor-webassembly/?ref=daveabrock.com">writes about lazy loading in Blazor WebAssembly</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/implement-a-webhook-framework-with-aspnetcore?ref=daveabrock.com">implements a webhook framework in ASP.NET Core</a>.</li><li>Mike Brind <a href="https://www.mikesdotnetting.com/article/353/implementing-a-custom-model-binder-in-razor-pages?ref=daveabrock.com">writes about implementing a custom model binder in Razor Pages</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-localization-with-shared-resources?ref=daveabrock.com">talks about possible pitfalls with localization in ASP.NET Core</a>.</li><li>Henrick Tissink <a href="https://dev.to/htissink/asp-net-core-api-path-versioning-197o?ref=daveabrock.com">talks about path versioning for ASP.NET Core APIs</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/611/implementing-health-checks-in-aspnet-core?ref=daveabrock.com">implements health checks in ASP.NET Core</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>Dominique St-Amand <a href="https://www.domstamand.com/migrating-to-the-new-csharp-azure-keyvault-sdk-libraries/?ref=daveabrock.com">migrates to the new C# Azure KeyVault SDK libraries</a>.</li><li>At CodeMaze, <a href="https://code-maze.com/azure-webjobs-in-app-service/?ref=daveabrock.com">using Azure WebJobs in .NET apps</a>.</li><li>Josh Hurley <a href="https://aws.amazon.com/blogs/developer/net-5-on-aws?ref=daveabrock.com">runs through .NET 5 on AWS</a>.</li><li>Christopher Christou <a href="https://aws.amazon.com/blogs/developer/exploring-net-5-with-the-aws-toolkit-for-visual-studio?ref=daveabrock.com">explores .NET 5 with the AWS Toolkit for Visual Studio</a>.</li><li>Justin Yoo <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/azure-functions-via-github-actions-with-no-publish-profile?ref=daveabrock.com">works with Azure Functions via GitHub Actions with no publish profile</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2020/11/09/implement-a-web-app-and-an-asp-net-core-secure-api-using-azure-ad-which-delegates-to-second-api/?ref=daveabrock.com">implements a web app and an ASP.NET Core secure API using Azure AD</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Miguel Bernard <a href="https://blog.miguelbernard.com/c-9-the-unknown-goodies/?ref=daveabrock.com">writes about the unknown goodies for C# 9</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/exceptiondispatchinfo-and-capturing-exceptions?ref=daveabrock.com">writes about ExceptionDispatchInfo and capturing exceptions</a>.</li><li>Carmel Eve <a href="https://endjin.com/blog/2020/11/design-patterns-in-csharp-the-facade-pattern.html?ref=daveabrock.com">writes about the Facade pattern in C#</a>.</li><li>David Hayden <a href="https://www.davidhayden.me/blog/top-level-programs-in-csharp-9?ref=daveabrock.com">writes about top-level programs in C# 9</a>.</li><li>Dominique St-Amand <a href="https://www.domstamand.com/csharp-ways-of-handling-when-being-throttled-by-an-api/?ref=daveabrock.com">talks about handling being throttled by an API in C#</a>.</li><li>Claudio Bernasconi <a href="https://www.claudiobernasconi.ch/2020/11/07/csharp-9-record-types-introduction-and-deep-dive/?ref=daveabrock.com">talks about C# 9 record types</a>.</li><li>Oren Eini <a href="https://ayende.com/blog/192325-A/always-profile-the-case-of-the-mysterious-performance-regression?ref=daveabrock.com">profiles to investigate performance regression</a> and also <a href="https://ayende.com/blog/192324-A/always-profile-the-hidden-cost-of-serializing-large-object-graphs-to-json?ref=daveabrock.com">writes about the cost of serializing large object graphs in JSON</a>.</li><li>Bohdan Stupak <a href="https://www.c-sharpcorner.com/article/using-spant-in-f-sharp/?ref=daveabrock.com">uses Span of T in F#</a>.</li><li>Mike Melanson <a href="https://thenewstack.io/this-week-in-programming-when-to-choose-f-over-rust/?ref=daveabrock.com">writes about when to choose F# over Rust</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Ian Bebbington <a href="https://ian.bebbs.co.uk/posts/UnoB2C?ref=daveabrock.com">writes about cross-platform app authentication with Azure AD B2C and the Uno Platform</a>.</li><li>Steve Smith <a href="https://ardalis.com/github-actions-from-cli/?ref=daveabrock.com">generates GitHub Actions from dotnet new templates</a>.</li><li>Khalid Abuhakmeh <a href="https://blog.jetbrains.com/dotnet/2020/11/09/diving-into-nuget-history-for-fun-and-community-insights/?ref=daveabrock.com">dives into NuGet history for fun and community insights</a>.</li><li>Iryne Somera <a href="https://stackify.com/best-5-tools-for-net-monitoring/?ref=daveabrock.com">discusses the best 5 tools for .NET monitoring</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2020/11/07/debugging-a-failed-api-request-and-defining-an-authorization-header-using-fiddler-everywhere?ref=daveabrock.com">debugs a failed API request with Fiddler</a>.</li><li>Idan Shatz <a href="https://oz-code.com/blog/production-debugging/debugging-net-applications-running-as-docker-microservices-from-intrusive-to-non-intrusive?ref=daveabrock.com">discusses the different ways to debug .NET apps running as Docker microservices</a>.</li><li>Adam Bertram <a href="https://octopus.com/blog/state-of-config-file-formats?ref=daveabrock.com">compares file formats between XML, YAML, JSON, and HCL</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Delpin Susai Raj <a href="https://xamarinmonkeys.blogspot.com/2020/11/xamarinforms-custom-titleview.html?ref=daveabrock.com">writes about a custom TitleView</a>.</li><li>Brandon Minnick <a href="https://codetraveler.io/2020/11/11/using-immutable-objects-with-sqlite-net/?ref=daveabrock.com">uses immutable objects with SQLite-Net</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/phone-dialer-sending-emails-sms-xamarin-forms?ref=daveabrock.com">writes about a phone dialer and sending emails and SMS</a>.</li><li>Damien Tohin Doumer Kake <a href="https://doumer.me/jwt-social-auth-with-asp-net-core-and-xamarin-essentials/?ref=daveabrock.com">works on JWT social auth with ASP.NET Core and Xamarin Essentials</a>.</li><li>David Britch <a href="https://www.davidbritch.com/2020/11/display-svgs-as-tabbedpage-tab-icons-in.html?ref=daveabrock.com">displays SVGs as TabbedPage tab icons</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><ul><li>The Xamarin Show <a href="https://www.xamarinpodcast.com/81?ref=daveabrock.com">talks about .NET 5</a>.</li><li>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1713&ref=daveabrock.com">talks with Billy Hollis about the ROI of good UX design</a>.</li><li>The Developers Road podcast <a href="https://www.developersroad.com/episodes/005-chris-woodruff/?ref=daveabrock.com">talks with Chris Woodruff about building your skillset</a>, and also <a href="https://www.developersroad.com/episodes/003-beth-massi/?ref=daveabrock.com">about building community with Beth Massi</a>.</li><li>The 6-Figure Developer podcast <a href="https://6figuredev.com/podcast/episode-169-welcome-back-ash-self-care-in-covid-times/?ref=daveabrock.com">talks about self-care in COVID times</a>.</li><li>At Technology and Friends, <a href="http://davidgiard.com/2020/11/09/ScottHanselmanOnProductivity.aspx?ref=daveabrock.com">David Giard talks with Scott Hanselman about productivity</a>.</li></ul><h2 id="-videos">🎥 Videos</h2><ul><li>Derek Comartin <a href="https://codeopinion.com/talking-c-performance-with-steve-gordon?ref=daveabrock.com">talks about C# performance with Steve Gordon</a>.</li><li>Jeff Fritz <a href="https://www.youtube.com/watch?v=HQT1GOA3hg8&ref=daveabrock.com">streams about SDK, project types, and testing</a>.</li><li>The ASP.NET Monsters <a href="https://www.youtube.com/watch?v=IAx1nsh5-Ao&ref=daveabrock.com">walks through Azure SQL Elastic Query</a>.</li><li>Data Exposed <a href="https://channel9.msdn.com/Shows/Data-Exposed/Leveling-Up-Your-Azure-SQL-Database-Deployments?ref=daveabrock.com">discusses Azure SQL database deployments</a> and also <a href="https://channel9.msdn.com/Shows/Data-Exposed/What-is-Azure-Arc-Enabled-SQL-Managed-Instance--Data-Exposed?ref=daveabrock.com">talks about Azure Arc Enabled SQL Managed Instance</a>.</li><li>Mads Kristensen <a href="https://www.youtube.com/watch?v=UHrAg3iKoe0&ref=daveabrock.com">walks through the new Git experience in Visual Studio 2019</a>.</li><li>A new Azure Enablement video series <a href="https://channel9.msdn.com/Shows/Azure-Enablement/Architect-successful-workloads-on-Azure--Introduction-Ep-1-Well-Architected-series?ref=daveabrock.com">talks about architecting successful workloads on Azure</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Simplify your ASP.NET Core API models with C# 9 records ]]></title>
        <description><![CDATA[ In this post, a quick tip about how to use records to simplify your API models. ]]></description>
        <link>https://www.daveabrock.com/2020/11/18/simplify-api-models-with-records/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe72</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Tue, 17 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1528590005476-4f5a6f2bdd9e?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fHJlY29yZHxlbnwwfHx8fDE2MTk4MzQxMjc&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>Out of all the new capabilities C# 9 brings, <a href="https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records?ref=daveabrock.com">records are my favorite</a>. With positional syntax, they are <a href="https://daveabrock.com/2020/11/02/csharp-9-records-immutable-default?ref=daveabrock.com">immutable by default</a>, which makes working with data classes a snap. I love the possibility of maintaining mutable state in C# where appropriate, like for business logic, and maintaining immutability (and data equality!) with records.</p><p>And did you know that <a href="https://docs.microsoft.com/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0&ref=daveabrock.com#model-binding-and-validation-with-c-9-record-types">with ASP.NET Core 5, model binding and validation supports record types</a>?</p><p>In the last post about <a href="https://daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis?ref=daveabrock.com">OpenAPI support in ASP.NET Core 5</a>, I used a sample project that worked with three <em>very simple</em> endpoints (or controllers): <code>Bands</code>, <code>Movies</code>, and <code>People</code>. Each model was in its own class, like this:</p><p><code>Band.cs</code>:</p><pre><code class="language-csharp">using System.ComponentModel.DataAnnotations;

namespace HttpReplApi.Models
{
    public class Band
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }
    }
}
</code></pre><p><code>Movie.cs</code>:</p><pre><code class="language-csharp">using System.ComponentModel.DataAnnotations;

namespace HttpReplApi.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }
        public int ReleaseYear { get; set; }

    }
}
</code></pre><p><code>Person.cs</code>:</p><pre><code class="language-csharp">using System.ComponentModel.DataAnnotations;

namespace HttpReplApi.Models
{
    public class Person
    {
        public int Id { get; set; }

        [Required]
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}
</code></pre><p>I can simplify these with using records instead. In the root, I’ll just create an <code>ApiModels.cs</code> file (I could have them in the controllers themselves, but that feels … messy):</p><pre><code class="language-csharp">using System.ComponentModel.DataAnnotations;

namespace HttpReplApi
{
    public record Band(int Id, [Required] string Name);
    public record Movie(int Id, [Required] string Name, int ReleaseYear);
    public record Person(int Id, [Required] string FirstName, string LastName);
}
</code></pre><p>After I <a href="https://github.com/daveabrock/HttpReplApi/blob/master/HttpReplApi/Data/SeedData.cs?ref=daveabrock.com">change my <code>SeedData</code> class to use positional parameters</a>, I am good to go—this took me about 90 seconds.</p><p>For some fun, if I grab a movie by ID, I can use the deconstruction support to get out my properties. (I’m using a discard since I’m not doing anything with the first argument, the <code>Id</code>.)</p><pre><code class="language-csharp">[HttpGet("{id}")]
public async Task&lt;ActionResult&lt;Movie&gt;&gt; GetById(int id)
{
    var movie = await _context.Movies.FindAsync(id);

    if (movie is null)
    {
        return NotFound();
    }

    var (_, name, year) = movie;
    _logger.LogInformation($"We have {name} from {year}");

    return movie;
}
</code></pre> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Use OpenAPI, Swagger UI, and HttpRepl in ASP.NET Core 5 to supercharge your API development ]]></title>
        <description><![CDATA[ In the latest post, we look at how easy it is to work with Swagger and HttpRepl in ASP.NET Core 5. ]]></description>
        <link>https://www.daveabrock.com/2020/11/16/httprepl-openapi-swagger-netcoreapis/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe71</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sun, 15 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1554744512-783e8dc69b10?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fHN1cGVyY2hhcmdlfGVufDB8fHx8MTYxOTgzNDE4NA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>When developing APIs in ASP.NET Core, you’ve got many tools at your disposal. Long gone are the days when you run your app from Visual Studio and call your <code>localhost</code> endpoint in your browser.</p><p>Over the last several years, a lot of tools have emerged that use the OpenAPI specification—most commonly, the <a href="https://github.com/swagger-api?ref=daveabrock.com">Swagger project</a>. Many ASP.NET Core API developers are familiar with <a href="https://swagger.io/tools/swagger-ui/?ref=daveabrock.com">Swagger UI</a>, a REST documentation tool that allows developers—either those developing it or developers consuming it—to interact with an API from a nice interface built from a project’s <code>swagger.json</code> file. In the .NET world, the functionality comes from <a href="https://www.nuget.org/packages/Swashbuckle.AspNetCore.Swagger/?ref=daveabrock.com">the Swashbuckle library</a>, at 80 million NuGet downloads and counting.</p><p>Additionally, I’ve been impressed by <a href="https://github.com/dotnet/HttpRepl?ref=daveabrock.com">the HttpRepl project</a>, which allows you explore your APIs from the command line. Different from utilities <a href="https://curl.se/?ref=daveabrock.com">like curl</a>, it allows you to explore APIs from the command-line similar to how you explore directories and files—all from a simple and lightweight interface. You can <code>cd</code> into your endpoints and call them quickly to achieve lightning-fast feedback. Even better, it has OpenAPI support (including <a href="https://github.com/dotnet/HttpRepl/pull/432?ref=daveabrock.com">the ability to perform OpenAPI validation on connect</a>).</p><p>While these utilities are not new with ASP.NET Core 5, it’s now much easier to get started. This post will discuss these tools.</p><p>Before you get started, you should have <a href="https://docs.microsoft.com/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio&ref=daveabrock.com">an ASP.NET Core API</a> ready—likely one with create-read-update-delete (CRUD) operations. Feel free <a href="https://github.com/daveabrock/HttpReplApi?ref=daveabrock.com">to clone and use mine</a>, if you’d prefer.</p><p>This post contains the following content.</p><ul><li><a href="#whats-the-difference-between-openapi-and-swagger">What’s the difference between OpenAPI and Swagger?</a></li><li><a href="#use-swagger-ui-with-aspnet-core-projects-by-default">Use Swagger UI with ASP.NET Core projects by default</a></li><li><a href="#use-httprepl-for-a-great-command-line-experience">Use HttpRepl for a great command-line experience</a></li><li><a href="#wrap-up">Wrap up</a></li></ul><h2 id="what-s-the-difference-between-openapi-and-swagger">What’s the difference between OpenAPI and Swagger?</h2><p>If you’ve heard OpenAPI and Swagger used interchangeably, you might be wondering what the difference is.</p><p>In short, OpenAPI is a specification used for documenting the capabilities of your API. Swagger is a set of tools from SmartBear (both open-source and commercial) that use the OpenAPI specification (like Swagger UI).</p><h2 id="use-swagger-ui-with-asp-net-core-projects-by-default">Use Swagger UI with ASP.NET Core projects by default</h2><p>For the uninitiated, the Swashbuckle project allows you to use Swagger UI—a tool that gives you the ability to render dynamic pages that allow to describe, document, and execute your API endpoints. Here’s how mine looks.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/swagger-ui-high-level.png" class="kg-image" alt="A high-level look at my Swagger page" loading="lazy" width="1462" height="1327" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/swagger-ui-high-level.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/swagger-ui-high-level.png 1000w, https://www.daveabrock.com/content/images/2021/05/swagger-ui-high-level.png 1462w" sizes="(min-width: 720px) 720px"></figure><p>And if you look at a sample POST (or any action), you’ll see a sample schema and response codes.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/movies-post.png" class="kg-image" alt="A sample post in Swagger" loading="lazy" width="1434" height="865" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/movies-post.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/movies-post.png 1000w, https://www.daveabrock.com/content/images/2021/05/movies-post.png 1434w" sizes="(min-width: 720px) 720px"></figure><p>In previous versions of ASP.NET Core, you had to manually download the Swashbuckle package, configure the middleware, and optionally change your <code>launchSettings.json</code> file. Now, with ASP.NET Core 5, that’s baked in automatically.</p><p>A big driver for the default OpenAPI support is <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/?ref=daveabrock.com#azure-api-management-import">the integration with Azure API Management</a>. Now with OpenAPI support, the Visual Studio publishing experience offers an additional step—to automatically import APIs into Azure API Management. To the cloud!</p><h3 id="how-it-s-enabled-and-how-you-can-opt-out">How it’s enabled, and how you can opt out</h3><p>If you create an ASP.NET Core 5 Web API project, you’ll see an <strong>Enable OpenAPI support</strong> checkbox that’s enabled by default. Just deselect it if you don’t want it.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/enable-open-api-support.png" class="kg-image" alt="Visual Studio OpenAPI checkbox" loading="lazy" width="390" height="345"></figure><p>If you create API projects using <code>dotnet new webapi</code> it’ll be baked in, too. (To opt out from OpenAPI support here, execute <code>dotnet new webapi --no-openapi true</code>.)</p><h3 id="verify-the-middleware-and-launchsettings-json">Verify the middleware and launchSettings.json</h3><p>After you create a project, we can see it’s all done for us. If you open your <em>.csproj</em> file, you’ll see the reference:</p><pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /&gt;
&lt;/ItemGroup&gt;
</code></pre><p>Then, in the <code>ConfigureServices</code> method in your <code>Startup.cs</code>, you’ll see your Swagger doc attributes defined and injected (this information will display at the top of your Swagger UI page). You can <a href="https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio&ref=daveabrock.com#api-info-and-description">definitely add more to this</a>.</p><pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddSwaggerGen(c =&gt;
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "HttpReplApi", Version = "v1" });
    });
}
</code></pre><p>And, in the <code>Configure</code> method in that same file you see the configuration of static file middleware:</p><pre><code class="language-csharp">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c =&gt;
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "HttpReplApi v1");
        });
    }

    // other services removed for brevity
}
</code></pre><p>Then, in <code>launchSettings.json</code>, you’ll see your project launches the Swagger UI page with the <code>/swagger</code> path, instead of a lonely blank page.</p><pre><code class="language-json">{
  "profiles": {
    "HttpReplApi": {
      "commandName": "Project",
      "dotnetRunMessages": "true",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
</code></pre><p>Now that you’ve got this set up for you, you can go to town on documenting your API. You can <a href="https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio&ref=daveabrock.com#xml-comments">add XML documentation</a> and <a href="https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio&ref=daveabrock.com#data-annotations">data annotations</a>—two easy ways to boost your Swagger docs. For example, the <code>Produces</code> annotations help define the status codes to expect.</p><p>From <a href="https://github.com/daveabrock/HttpReplApi/blob/master/HttpReplApi/Controllers/BandsController.cs?ref=daveabrock.com">my <code>BandsController.cs</code></a>, I use a lot of <a href="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.producesresponsetypeattribute?view=aspnetcore-5.0&ref=daveabrock.com"><code>Produces</code> annotations</a>:</p><pre><code class="language-csharp">[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task&lt;IActionResult&gt; Delete(int id)
{
  // delete by id logic
}
</code></pre><p>I love that this is available by default, but would love to see more OpenAPI scaffolding in the templates. It might be a little opinionated, but adding some <code>Produces</code> annotations in the default <code>WeatherForecast</code> controller would allow for a better developer experience with Swagger out of the box (since it is now out of the box).</p><h2 id="use-httprepl-for-a-great-command-line-experience">Use HttpRepl for a great command-line experience</h2><p>You can use HttpRepl to test your ASP.NET Core Web APIs from the command-line quickly and easily.</p><h3 id="install">Install</h3><p>You install HttpRepl as a .NET Core Global Tool, by executing the following from the .NET Core CLI:</p><pre><code>dotnet tool install -g Microsoft.dotnet-httprepl
</code></pre><p>As a global tool, you can run it from anywhere.</p><h3 id="basic-operations">Basic operations</h3><p>To get started, I can launch my app and connect to it from <code>httprepl</code>:</p><pre><code>httprepl https://localhost:5001
</code></pre><p>If I do an <code>ls</code> or <code>dir</code>, I can look at my endpoints:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/localhost-dir.png" class="kg-image" alt="Doing a dir from the root" loading="lazy" width="445" height="169"></figure><p>To execute a get on my <code>/bands</code> endpoint, I get a response payload, with headers:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/get-bands.png" class="kg-image" alt="Doing a GET on bands" loading="lazy" width="667" height="747" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/get-bands.png 600w, https://www.daveabrock.com/content/images/2021/05/get-bands.png 667w"></figure><p>Then, I could say <code>get {id}</code> to get a <code>Band</code> by id:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/get-eagles.png" class="kg-image" alt="Doing a get by id" loading="lazy" width="676" height="345" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/get-eagles.png 600w, https://www.daveabrock.com/content/images/2021/05/get-eagles.png 676w"></figure><h3 id="modify-data-with-a-default-editor">Modify data with a default editor</h3><p>What happens when you want to update some data? You could do something like this…</p><pre><code>post --content "{"id":2,"name":"Tool"}"
</code></pre><p>…but that’s only manageable for the simplest of scenarios. You’ll want to set up a default text editor to work with request bodies. You can construct a request, then HttpRepl will wait for you to save and close the tab or window.</p><p>In HttpRepl, you can set various preferences, including a default editor. I’m using Visual Studio Code on Windows, so would execute something like this…</p><pre><code>pref set editor.command.default "C:\Program Files\Microsoft VS Code\Code.exe"
</code></pre><p>If using Visual Studio Code, you’ll also want to pass a `–wait flag so VS Code waits for a closed file before returning.</p><pre><code>pref set editor.command.default.arguments "--wait"
</code></pre><p>You can also <a href="https://docs.microsoft.com/aspnet/core/web-api/http-repl/?view=aspnetcore-5.0&tabs=windows&ref=daveabrock.com#view-the-settings">set various other preferences</a>, like color and indentation.</p><p>Now, when you say <code>post</code> from your endpoint, VS Code opens a <code>.tmp</code> file with a default request body, then waits for you to save and close it. The POST should process successfully.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/post-brothers.png" class="kg-image" alt="Performing a post" loading="lazy" width="667" height="409" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/post-brothers.png 600w, https://www.daveabrock.com/content/images/2021/05/post-brothers.png 667w"></figure><p>With the ID in hand, I can do the same steps to modify using <code>put 5</code>, then run <code>get 5</code> to confirm my changes:</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/put-get-brothers.png" class="kg-image" alt="Performing a put" loading="lazy" width="672" height="633" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/put-get-brothers.png 600w, https://www.daveabrock.com/content/images/2021/05/put-get-brothers.png 672w"></figure><p>If I want to delete my resource, I can execute <code>delete 5</code> and it’ll be gone. I tweeted a video of me cycling through the CRUD operations.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I love HttpRepl. Check it out: going through the big four HTTP verbs in just 34 seconds! <br><br>This isn&#39;t a race, and your models will be much more complex obviously, but it&#39;s a good demo of how fast your API development feedback can be.<br><br>cc/ <a href="https://twitter.com/Scott_Addie?ref_src=twsrc%5Etfw&ref=daveabrock.com">@Scott_Addie</a> <a href="https://twitter.com/bradygaster?ref_src=twsrc%5Etfw&ref=daveabrock.com">@bradygaster</a> <a href="https://twitter.com/hashtag/dotnet?src=hash&ref_src=twsrc%5Etfw&ref=daveabrock.com">#dotnet</a> <a href="https://t.co/6w41j5esOk?ref=daveabrock.com">pic.twitter.com/6w41j5esOk</a></p>&mdash; Dave Brock (@daveabrock) <a href="https://twitter.com/daveabrock/status/1328413854859202561?ref_src=twsrc%5Etfw&ref=daveabrock.com">November 16, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h3 id="remove-repetition-with-a-script">Remove repetition with a script</h3><p>If I find myself using the same test scenarios, I can throw these commands in a <em>.txt</em> file instead. For example, I created an <em>api-script.txt</em> file that I execute from the root of my <code>httprepl</code> session:</p><pre><code class="language-txt">cd Bands
ls
get
post --content "{"id": 20, "name": "The Blue Medium Chili Peppers"}"
put 20 --content "{"id": 20, "name": "The Red Mild Chili Peppers"}"
get 20
delete 20
</code></pre><p>Then I can run it using <code>run {path_to_script}</code>.</p><h3 id="learn-more-about-configuring-httprepl">Learn more about configuring HttpRepl</h3><p>This is a straightforward walkthrough, but you can do a whole lot more. I was impressed with the robust configuration options. This includes manually pointing to the OpenAPI description, verbose logging, setting preferences, configuring formatting, customizing headers and streaming, logging to a file, using additional HTTP verbs, testing secured endpoints, accessing Azure-hosted endpoints, and even configuring your tools to launch HttpRepl.</p><p>All this information can be found at the <a href="https://docs.microsoft.com/en-us/aspnet/core/web-api/http-repl/?view=aspnetcore-5.0&tabs=windows&ref=daveabrock.com#manually-point-to-the-openapi-description-for-the-web-api">official doc,</a> wonderfully done by <a href="https://daveabrock.com/2020/08/15/dev-discussions-scott-addie?ref=daveabrock.com">our friend</a> <a href="https://twitter.com/Scott_Addie?ref=daveabrock.com">Scott Addie</a>.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we talked about the difference between OpenAPI and Swagger, using Swagger UI by default in your ASP.NET Core Web API projects, and how to use the HttpRepl tool.</p><p>As always, let me know your experience with these tools.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ The .NET Stacks #25: .NET 5 officially launches tomorrow ]]></title>
        <description><![CDATA[ This week, .NET 5 ships, and are C# 9 records actually immutable by default? ]]></description>
        <link>https://www.daveabrock.com/2020/11/13/dotnet-stacks-25/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe70</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Thu, 12 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://www.daveabrock.com/content/images/2021/05/THE-.NET-STACKS-20.png" medium="image"/>
        <content:encoded><![CDATA[ <p>With .NET 5 shipping this week, it’s going to be such a release.</p><p>On tap this week:</p><ul><li>.NET 5 officially launches tomorrow</li><li>Are C# 9 records actually immutable by default?</li><li>Last week in the .NET world</li></ul><h1 id="-net-5-officially-launches-tomorrow">.NET 5 officially launches tomorrow</h1><p>After eight preview releases, two release candidates, and some tears—by me, working on the early preview bits—it’s finally happening: .NET 5 ships tomorrow. Of course, the release candidates shipped with a go-live license but everything becomes official tomorrow. You’ll be able to download official bits and we <a href="https://twitter.com/coolcsh/status/1325218584272936960?ref=daveabrock.com">might even see it working with Azure App Service</a> (no pressure). There’s also .NET Conf, where you’ll get to <a href="https://www.dotnetconf.net/?ref=daveabrock.com">geek out on .NET 5 for three straight days</a>.</p><p>It’s been a long time coming—and it feels a bit longer with all this COVID-19 mess, doesn’t it? Even so, the “Introducing .NET 5” post <a href="https://devblogs.microsoft.com/dotnet/introducing-net-5/?ref=daveabrock.com">hit about 18 months ago</a>—and with it, the promise of a unified platform (with Xamarin hitting .NET 6 because of pandemic-related resourcing constraints). We’re talking a single .NET runtime and framework however you’re developing an app, and a consistent release schedule (major releases every November).</p><p>Of course, this leads to questions about what it means to say .NET Framework, .NET Standard, and .NET Core—not to mention how the support will work. I covered <a href="https://daveabrock.com/2020/10/31/dotnet-stacks-23?ref=daveabrock.com">those not-sexy-but-essential questions two weeks ago</a>.</p><p>Since I started this newsletter in May (we’re at Issue #25!), we’ve been dissecting what’s new week by week. (You can <a href="https://daveabrock.com/tags/?ref=daveabrock.com#dotnet-stacks">look at the archives on my site</a>.) For a condensed version, here’s my favorite things about .NET 5—both big and small. (This is a little like talking about your favorite song or movie, so your opinions might differ.)</p><h2 id="custom-json-console-logger">Custom JSON console logger</h2><p>ASP.NET Core now ships with a <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-preview-8/?ref=daveabrock.com#json-console-logger">built-in JSON formatter</a> that emits <em>structured</em> JSON logs to the console. Is this a huge change? No. Will it make my life easier on a daily basis. You know it.</p><h2 id="enhanced-dotnet-watch-support">Enhanced dotnet watch support</h2><p>In .NET 5, running <code>dotnet watch</code> on an ASP.NET Core project now launches the default browser and auto-refreshes on save. This is a great quality-of-life developer experience improvement, as we patiently await for this to hit Visual Studio.</p><h2 id="open-api-spec-on-by-default-for-asp-net-core-projects">Open API spec on by default for ASP.NET Core projects</h2><p>When you create a new API project using <code>dotnet new webapi</code>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/?ref=daveabrock.com#open-api-specification-on-by-default">you’ll see OpenAPI output enabled by default</a>—meaning you won’t have to manually configure the Swashbuckle library and the Swagger UI page is enabled in development mode. This also means that F5 now <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/?ref=daveabrock.com#better-f5-experience-for-web-api-projects">takes you straight to the Swagger page instead of a lonely 404</a>.</p><h2 id="performance-improvements">Performance improvements</h2><p>If you have some time to kill and aren’t scared off by low-level details, I’d highly recommend <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/?ref=daveabrock.com">Stephen Toub’s July post on .NET 5 performance improvements</a>. In short, text operations are 3x-5x faster, regular expressions are 7x faster with multiline expressions, serializing arrays and complex types in JSON are faster by 2x-5x, and much more.</p><h2 id="ef-core-5-updates">EF Core 5 updates</h2><p>EF Core 5 is also shipping with a ton of new features. <a href="https://docs.microsoft.com/ef/core/what-is-new/ef-core-5.0/plan?ref=daveabrock.com">Where to begin</a>? Well, there’s many-to-many navigation properties (skip navigations), table-per-type inheritance mapping, filtered and split includes, general query enhancements, event counters, <code>SaveChanges</code> events, savepoints, split queries for related collections, database collations, and … well, <a href="https://docs.microsoft.com/ef/core/what-is-new/ef-core-5.0/whatsnew?ref=daveabrock.com">check out the What’s New doc for the full treatment</a>.</p><h2 id="single-file-apps">Single file apps</h2><p>Single-file apps are now supported with .NET 5, meaning you can publish and distribute an app in a single executable. <a href="https://github.com/dotnet/runtime/issues/36590?ref=daveabrock.com">Hooray</a>.</p><h2 id="blazor-updates">Blazor updates</h2><p>.NET 5 ships with a ton of Blazor improvements, including <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-preview-8/?ref=daveabrock.com#css-isolation-for-blazor-components">CSS isolation</a>, <a href="https://docs.microsoft.com/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0&ref=daveabrock.com#blazor-javascript-isolation-and-object-references">JavaScript isolation</a>, <a href="https://docs.microsoft.com/aspnet/core/blazor/components/virtualization?ref=daveabrock.com">component virtualization</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/?ref=daveabrock.com#blazor-support-for-ontoggle-event">toggle event support</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-preview-7/?ref=daveabrock.com#blazor-webassembly-apps-now-target-net-5">switching WebAssembly apps from Mono to .NET 5</a>, <a href="https://docs.microsoft.com/aspnet/core/blazor/webassembly-lazy-load-assemblies?ref=daveabrock.com">lazy loading</a>, <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/?ref=daveabrock.com#blazor-webassembly-prerendering">server pre-rendering</a>, and so on.</p><h2 id="c-9">C# 9</h2><p>I’m super excited for the release of C# 9, especially the embracing of paradigms common in functional programming. With <a href="https://daveabrock.com/2020/06/29/c-sharp-9-deep-dive-inits?ref=daveabrock.com">init-only properties</a> and <a href="https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records?ref=daveabrock.com">records</a>, C# developers have the flexibility to easily use immutable constructs in a mutable-by-design language. It might take some getting used to, but I love the possibilities. I see a lot of promise in keep the real-world object modeling, but also introducing immutability where treating objects as data makes sense.</p><p>(There’s also great improvements with <a href="https://daveabrock.com/2020/07/09/c-sharp-9-top-level-programs?ref=daveabrock.com">top-level programs</a>, <a href="https://daveabrock.com/2020/07/06/c-sharp-9-pattern-matching?ref=daveabrock.com">pattern matching</a>, and <a href="https://daveabrock.com/2020/07/14/c-sharp-9-target-typing-covariants?ref=daveabrock.com">target typing</a>.)</p><h1 id="are-c-9-records-actually-immutable-by-default">Are C# 9 records actually immutable by default?</h1><p>Speaking of records, there seems to be some confusion on if C# 9 records are immutable by default. The answer is: yes, and no. Records are immutable by default when using positional arguments. When you want to use them with object initializers, they aren’t—which makes sense, since initializers are more flexible in how objects are constructed.</p><p>Feel free to <a href="https://daveabrock.com/2020/11/02/csharp-9-records-immutable-default?ref=daveabrock.com">check out my post for the full details</a>.</p><h1 id="happy-birthday-dad">Happy birthday, Dad</h1><p>Someone has turned a lucky … um … well, numbers don’t matter, do they? Happy Birthday, Dad. You can thank him for … <em>waves hands</em> … all this. I’m not sure what I’d be doing without him encouraging my nerdy tendencies during my most awkward years, but I’m glad I’ll never have to find out. Have a good day, mister.</p><p>When I said I like to wear many hats, I didn’t mean this one.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/dad-and-me.jpeg" class="kg-image" alt="Picture with mom" loading="lazy" width="422" height="284"></figure><p>(Don’t worry, this is the last birthday wish. Back to regularly scheduled programming.)</p><h1 id="-last-week-in-the-net-world">🌎 Last week in the .NET world</h1><h2 id="-the-top-3">🔥 The Top 3</h2><ul><li>Beth Massi <a href="https://devblogs.microsoft.com/dotnet/net-5-0-launches-at-net-conf-november-10-12?ref=daveabrock.com">previews .NET Conf from November 10-12</a>.</li><li>Damien Bowden <a href="https://damienbod.com/2020/11/02/implement-a-blazor-full-text-search-using-azure-cognitive-search/?ref=daveabrock.com">implements a Blazor full text search using Azure Cognitive Search</a>.</li><li>Irina Scurtu <a href="https://irina.codes/net-core-with-nginx-on-linux/?ref=daveabrock.com">works with .NET Core with nginx on Linux</a>, and also <a href="https://irina.codes/net-api-as-a-linux-service/?ref=daveabrock.com">talks about using a .NET API as a Linux service</a>.</li></ul><h2 id="-announcements">📢 Announcements</h2><ul><li>Eilon Lipton <a href="https://devblogs.microsoft.com/aspnet/unified-ui-mobile-blazor-bindings-preview-5?ref=daveabrock.com">runs through preview 5 of Blazor Mobile Bindings</a>.</li><li>AWS has <a href="https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-the-aws-sdk-for-net-version-1?ref=daveabrock.com">stopped supporting AWS SDK for .NET version 1</a>.</li></ul><h2 id="-community-and-events">📅 Community and events</h2><ul><li>Microsoft Learn has launched a <a href="https://docs.microsoft.com/learn/challenges?id=58bdb63e-96b6-4598-afd1-d350438476b5&WT.mc_id=dotnet-10219-masalnik&_lrsc=89013caa-3a23-4196-b218-d4c4e53fa883&ref=daveabrock.com">.NET Learn Challenge</a>.</li><li>The .NET Docs show <a href="https://www.youtube.com/watch?v=JBvGX2k23Jc&ref=daveabrock.com">talks about navigating ML.NET with Bri Achtman and Luis Quintanilla</a>.</li><li>Just two .NET standups this week: Machine Learning <a href="https://www.youtube.com/watch?v=0DNWLorVIh4&ref=daveabrock.com">talks TorchSharp &amp; Tensor programming</a>, and Xamarin <a href="https://www.youtube.com/watch?v=Y0bEAy6yxMQ&ref=daveabrock.com">discusses Mobile Blazor Bindings</a>.</li></ul><h2 id="-asp-net-core-blazor">😎 ASP.NET Core / Blazor</h2><ul><li>Dave Brock (ahem) <a href="https://daveabrock.com/2020/11/08/blast-off-blazor-update-head?ref=daveabrock.com">talks about updating the HTML head from a Blazor component</a>.</li><li>Jon Hilton <a href="https://www.telerik.com/blogs/migrating-mvc-to-blazor?ref=daveabrock.com">talks about migrating from MVC to Blazor</a>.</li><li>Marinko Spasojevic <a href="https://code-maze.com/use-browser-functionalities-with-blazor-webassembly/?ref=daveabrock.com">uses browser functionalities</a> and also <a href="https://code-maze.com/how-to-call-csharp-methods-from-javascript-in-blazor-webassembly/?ref=daveabrock.com">calls C# methods from JavaScript in Blazor WebAssembly</a>.</li><li>Kristoffer Strube <a href="https://blog.elmah.io/how-to-send-push-notifications-to-a-browser-in-asp-net-core/?ref=daveabrock.com">sends push notifications to a browser in ASP.NET Core</a>.</li><li>Paul Michaels <a href="https://www.pmichaels.net/2020/10/31/tag-helper-not-working/?ref=daveabrock.com">documents some recent tag helper issues</a>.</li><li>Sam Xu <a href="https://devblogs.microsoft.com/odata/routing-in-asp-net-core-8-0-preview?ref=daveabrock.com">introduces ASP.NET Core OData 8.0 routing</a>.</li><li>Imar Spaanjaars <a href="https://imar.spaanjaars.com/609/implementing-health-checks-in-aspnet-framework-applications?ref=daveabrock.com">discusses implementing health checks in ASP.NET Framework apps</a>.</li><li>Jason Gaylord discusses building APIs with GraphQL and .NET Core <a href="https://www.jasongaylord.com/blog/2020/11/03/build-api-graphql-dotnet-core-part-1?ref=daveabrock.com">post 1</a>, <a href="https://www.jasongaylord.com/blog/2020/11/04/build-api-graphql-dotnet-core-part-2?ref=daveabrock.com">post 2</a>.</li><li>Ricardo Peres <a href="https://weblogs.asp.net/ricardoperes/asp-net-core-pitfalls-areas?ref=daveabrock.com">talks about some gotchas with ASP.NET Core areas</a>.</li></ul><h2 id="-the-cloud">⛅ The cloud</h2><ul><li>David Grace <a href="https://www.roundthecode.com/dotnet/asp-net-core-web-hosting/dealing-asp-net-core-web-api-access-restrictions-errors-azure?ref=daveabrock.com">deals with ASP.NET Core Web API access restrictions and errors in Azure</a>.</li><li>Justin Yoo <a href="https://techcommunity.microsoft.com/t5/apps-on-azure/github-actions-dns-amp-ssl-certificate-on-azure-functions?ref=daveabrock.com">writes about GitHub Actions, DNS, and SSL certs on Azure Functions</a>.</li><li>Tore Nestenius <a href="https://www.edument.se/en/blog/post/storing-the-asp-net-core-data-protection-key-ring-in-azure-key-vault?ref=daveabrock.com">stores the ASP.NET Core Data Protection Key Ring in Azure Key Vault</a>.</li><li>Laurent Bugnion <a href="https://galasoft.ch/posts/2020/11/best-practice-when-naming-durable-functions-in-c?ref=daveabrock.com">talks about the best practice when naming Durable Functions in C#</a>.</li><li>Joe “Hulk Hogan” Guadagno works with <a href="https://www.josephguadagno.net/2020/11/03/nlog-dependency-injection-and-azure-functions-oh-my?ref=daveabrock.com">NLog, dependency injection, and Azure Functions</a>.</li></ul><h2 id="-languages">📔 Languages</h2><ul><li>Dave Brock (ahem) asks: <a href="https://daveabrock.com/2020/11/02/csharp-9-records-immutable-default?ref=daveabrock.com">are C# 9 records immutable by default</a>?</li><li>Anthony Giretti <a href="https://anthonygiretti.com/2020/11/01/introducing-c-9-extension-getenumerator-support-for-foreach-loops/?ref=daveabrock.com">works with GetEnumerator extension support for foreach in C# 9</a>.</li><li>Jiří Činčura <a href="https://www.tabsoverspaces.com/233842-new-environment-processid-in-net-5?ref=daveabrock.com">discusses the new Environment.ProcessId in .NET 5</a>.</li><li>Steve Gordon <a href="https://www.stevejgordon.co.uk/additional-http-sockets-dns-and-tls-telemetry-in-dotnet-5?ref=daveabrock.com">discusses additional HTTP, sockets, DNS, and TLS telemetry in .NET 5</a>.</li><li>Thomas Levensque <a href="https://thomaslevesque.com/2020/10/30/using-csharp-9-records-as-strongly-typed-ids/?ref=daveabrock.com">uses C# 9 records as strongly-typed IDs</a>.</li><li>Khalid Abuhakmeh <a href="https://khalidabuhakmeh.com/looking-at-system-io-path?ref=daveabrock.com">takes a look at System.IO.Path</a>.</li></ul><h2 id="-tools">🔧 Tools</h2><ul><li>Derek Comartin <a href="https://codeopinion.com/cqrs-myths-3-most-common-misconceptions?ref=daveabrock.com">talks about CQRS myths</a>.</li><li>Tim Heuer <a href="https://timheuer.com/blog/generate-github-actions-workflow-from-cli/?ref=daveabrock.com">generates a GitHub Actions workflow file from the dotnet CLI</a>.</li><li>Kunal Chowdhury <a href="https://www.kunal-chowdhury.com/2020/11/advanced-git-tips.html?ref=daveabrock.com">offers some advanced Git tips</a>.</li></ul><h2 id="-xamarin">📱 Xamarin</h2><ul><li>Vicente Gerardo Guzmán Lucio <a href="https://www.syncfusion.com/blogs/post/protecting-sensitive-data-in-the-background-in-xamarin-forms.aspx?ref=daveabrock.com">protects sensitive data in the background</a>.</li><li>Leomaris Reyes <a href="https://www.telerik.com/blogs/best-xamarin-forms-app-examples?ref=daveabrock.com">walks through the best Xamarin Forms app examples</a>, and also <a href="https://www.telerik.com/blogs/getting-started-with-text-to-speech-in-xamarin-forms?ref=daveabrock.com">gets started with text-to-speech</a>.</li></ul><h2 id="-podcasts">🎤 Podcasts</h2><p>The .NET Rocks podcast <a href="https://www.dotnetrocks.com/default.aspx?ShowNum=1712&ref=daveabrock.com">discusses Cake 1.0 with Mattias Karlsson</a>.</p><h2 id="-videos">🎥 Videos</h2><ul><li>The Loosely Coupled Show <a href="https://www.youtube.com/watch?v=pZx0X2hDx7A&ref=daveabrock.com">asks: should you learn a functional programming language</a>?</li><li>The Visual Studio Toolbox <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/GitHub-Codespaces?ref=daveabrock.com">talks about GitHub Codespaces</a>.</li><li>The folks at Compositional IT <a href="https://www.youtube.com/watch?v=kLoLl3kqpfk&feature=youtu.be&ab_channel=CompositionalIT&ref=daveabrock.com">talk quickly about SAFE Stack web apps pn Azure Static Web Apps</a>.</li><li>Over at ON.NET, they talk about <a href="https://www.youtube.com/watch?v=GfTlbjuWU5Q&ref=daveabrock.com">the inner loop with VS Code and GitHub</a>, and also <a href="https://www.youtube.com/watch?v=iDAYdrFHqGU&ref=daveabrock.com">real-time data fetching with GraphQL and Blazor</a>.</li></ul> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Blast Off with Blazor: Use .NET 5 to update the HTML head from a Blazor component ]]></title>
        <description><![CDATA[ In the latest post, we&#39;ll learn how to update the HTML head dynamically using .NET 5. ]]></description>
        <link>https://www.daveabrock.com/2020/11/08/blast-off-blazor-update-head/</link>
        <guid isPermaLink="false">608c3e3df4327a003ba2fe6f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Dave Brock ]]></dc:creator>
        <pubDate>Sat, 07 Nov 2020 18:00:00 -0600</pubDate>
        <media:content url="https://images.unsplash.com/photo-1494022299300-899b96e49893?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDEwfHxhc3Ryb25hdXR8ZW58MHx8fHwxNjE5ODMzNjQ5&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded><![CDATA[ <p>So far in this series, we’ve <a href="https://daveabrock.com/2020/10/26/blast-off-blazor-intro?ref=daveabrock.com">walked through a project intro</a> and also <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com">got our feet wet with our first component</a>.</p><p>Today, we’re going to take a look at a welcome .NET 5 feature in Blazor: the ability to <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-preview-8/?ref=daveabrock.com#influencing-the-html-head-in-blazor-apps">update your HTML head on the fly</a> without the need for JavaScript interoperability.</p><p>When I speak of updating the HTML head, I’m referring to what’s inside the <code>&lt;head&gt;</code> tag in your <code>index.html</code> file. You can now use the following native Blazor components to dynamically update the HTML head:</p><ul><li><code>&lt;Title&gt;</code> - the title of the document. You’d use this if you want to update your user on any updates, especially if they are busy with other tabs. You’ve probably seen this with updates for new email messages or new chat notifications.</li><li><code>&lt;Link&gt;</code> - gives you the ability to link to other resources. For example, you might want to dynamically update this to change stylesheets when the user clicks a button to specify light or dark mode.</li><li><code>&lt;Meta&gt;</code> - allows you to specify a variety of information for things like SEO, social cards, and RSS information.</li></ul><p>Since these are individual components, you can definitely use them together in your code. Following the email example, you could update the title bar with an unread message count and also change the “you have a message” favicon appropriately.</p><p>In this post, we’re going to dynamically update the HTML <code>&lt;title&gt;</code> tag from our Blazor component. And since we’re already working with the browser’s title bar, I’ll walk you through adding favicons to our site.</p><p>This post contains the following content.</p><ul><li><a href="#dynamically-set-page-title">Dynamically set page title</a></li><li><a href="#add-favicons-to-our-app">Add favicons to our app</a></li><li><a href="#what-about-the-tests">What about the tests?</a></li><li><a href="#wrap-up">Wrap up</a></li><li><a href="#resources">Resources</a></li></ul><h2 id="dynamically-set-page-title">Dynamically set page title</h2><p>As I mentioned, we’re going to dynamically update the <code>&lt;title&gt;</code> tag of our component. Before we do that, we’ll first need to add a package reference, add a script reference, and reference the new package in our project.</p><h3 id="add-package-reference">Add package reference</h3><p>From the <code>Client</code> directory of our project, open your terminal and add a package reference using the <code>dotnet</code> CLI.</p><pre><code>dotnet add package Microsoft.AspNetCore.Components.Web.Extensions --prerelease
</code></pre><p><strong>Heads up!</strong> At this time, the <code>--prerelease</code> flag is required.</p><h3 id="add-script-reference">Add script reference</h3><p>In the <code>index.html</code> file in <code>wwwroot</code>, add the following reference:</p><pre><code class="language-html">&lt;script src="_content/Microsoft.AspNetCore.Components.Web.Extensions/headManager.js"&gt;&lt;/script&gt;
</code></pre><h3 id="reference-the-project">Reference the project</h3><p>We can use one of two options to reference the new package in our app. Our first option is a direct <code>@using</code> in the <code>Index.razor</code> component:</p><pre><code>@using Microsoft.AspNetCore.Components.Web.Extensions.Head
</code></pre><p>Or, we can include it in our <code>_Imports.razor</code> file. The <code>_Imports.razor</code> file, which sits at the root of our <code>Client</code> project, allows us to reference our app’s imports globally. That way, we won’t have to manually add shared references to all our components that need it. With my new addition, here’s what my <code>_Imports.razor</code> file looks like now:</p><pre><code>@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using Client
@using Client.Shared
@using Data
@using Microsoft.AspNetCore.Components.Web.Extensions.Head
</code></pre><p>Either method works, but I’m going with the latter option for reusability. We’re now ready to set the page title.</p><h3 id="set-the-page-title">Set the page title</h3><p>Here’s what we’ll do: while I’m waiting for the NASA Astronomy Picture of the Day (APOD) API call to return, our title bar will say <em>Blasting off…</em>. Then, when we get a response back, it’ll say <em>New! From YEAR!</em>, where <em>YEAR</em> is the year of the image. This value comes from the <code>Year</code> property returned by the API.</p><p>In the <code>@code</code> section of our <code>Index.razor</code> component, add the following code to parse the year from our <code>Date</code> property:</p><pre><code class="language-csharp">private int GetYear(DateTime date)
{
    return date.Year;
}
</code></pre><p>Then, we can use a one-line ternary statement to return a message based on us whether we get a response from the API.</p><pre><code>private string GetPageTitle()
{
    return image is null ? "Blasting off..." : $"New! From {GetYear(image.Date)}!";
}
</code></pre><p>Now, all that’s left is to drop the <code>&lt;Title&gt;</code> component at the top of our markup, and call our logic to change the title text.</p><pre><code class="language-html">&lt;Title Value="@GetPageTitle()"&gt;&lt;/Title&gt;
</code></pre><p>Here’s a GIF of our update in action. (I set a <code>Thread.Sleep(1000)</code> for demonstration purposes, but I don’t recommend it in practice obviously.)</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/SetTitleBar.gif" class="kg-image" alt="Our title bar in action" loading="lazy" width="1042" height="1080"></figure><h3 id="how-it-all-works">How it all works</h3><p>Before .NET 5, updating the HTML head dynamically required the use of JavaScript interoperability.</p><p>You’d likely drop the following JavaScript at the bottom of your <code>index.html</code>:</p><pre><code>&lt;script&gt;
    function SetTitle(title) {
        document.title = title;
    }
&lt;/script&gt;
</code></pre><p>Then, you’d have to inject JavaScript interop and probably create a special component for it:</p><pre><code class="language-csharp">@inject IJSRuntime JSRuntime

// markup here...

@code {
    [Parameter]
    public string Value { get; set; }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await JSRuntime.InvokeVoidAsync("SetTitle", Value);
    }
}
</code></pre><p>Then, you’d add the component on your page to update the title bar dynamically, where your <code>GetPageTitle</code> method would do what it needs to populate the title.</p><pre><code>&lt;PageTitle Value="@GetPageTitle()" /&gt;
</code></pre><p>In .NET 5, this still happens—it’s just abstracted away from you. If you <a href="https://github.com/aspnet/AspLabs/blob/master/src/Components.Web.Extensions/HeadManagement/Title.cs?ref=daveabrock.com">take a look at the source code</a> for the <code>&lt;Title&gt;</code> component, it injects an <code>IJSRuntime</code> and takes a <code>Value</code>—just as you’ve done before. Then, in the <code>OnAfterRenderAsync</code> <a href="https://docs.microsoft.com/aspnet/core/blazor/components/lifecycle?view=aspnetcore-3.1&ref=daveabrock.com#after-component-render">component lifecycle method</a>, it sets the title by calling the <code>headManager.js</code> file, where you’ll see:</p><pre><code class="language-javascript">export function setTitle(title) {
  document.title = title;
}
</code></pre><p><strong>Note</strong>: The <a href="https://docs.microsoft.com/aspnet/core/blazor/components/lifecycle?view=aspnetcore-3.1&ref=daveabrock.com#after-component-render"><code>OnAfterRenderAsync</code> method is called</a> after a component has finished rendering.</p><p>So, this isn’t doing anything too magical. It’s doing it out-of-the-box and giving you one less component to maintain.</p><p>With that done, let’s add favicons to our app.</p><h2 id="add-favicons-to-our-app">Add favicons to our app</h2><p>When you create a Blazor app (or any ASP.NET Core app, for that matter), a bland <code>favicon.ico</code> file is dropped in your <code>wwwroot</code> directory. (For the uninitiated, <a href="https://en.wikipedia.org/wiki/Favicon?ref=daveabrock.com">a favicon</a> is the small icon in the top-left corner of your browser tab, right next to the page title.) This might lead you to believe that if you want to use favicons, you can either use that file or overwrite it with one of your own—then move on with your life.</p><p>While you <em>can</em> do that, you probably shouldn’t. These days you’re dealing with different browser requirements and multiple platforms (Windows, iOS, Mac, Android) where just one <em>favicon.ico</em> will not get the job done. For example, iOS users can pin a site to their homescreen—and iOS will grab your favicon icon as the “app” image.</p><p>Thanks to Andrew Lock’s <a href="https://andrewlock.net/adding-favicons-to-your-asp-net-core-website-with-realfavicongenerator/?ref=daveabrock.com">wonderful post on the topic</a>, I went over to the <a href="https://realfavicongenerator.net/?ref=daveabrock.com">RealFaviconGenerator</a> for assistance. (If you want more details on the process, like how to create your own, check out his post.)</p><p>Before we do that, we’ll need to pick a new image.</p><p>Did you know the .NET team has a <a href="https://github.com/dotnet/brand?ref=daveabrock.com">branding GitHub repository</a> where you can look at logos, presentation templates, wallpapers, and a bunch of illustrations of the purple .NET bot? For our example, we’ll use the <a href="https://github.com/dotnet/brand/blob/master/dotnet-bot-illustrations/dotnet-bot/dotnet-bot_jetpack-faceing-right.png?ref=daveabrock.com">bot using a jetpack</a> because—obviously. We’re blasting off, after all.</p><p>Let’s also update our header icon to this image, too. After dropping the file in our <code>wwwroot/assets/img</code> <a href="https://github.com/daveabrock/NASAImageOfDay/tree/main/Client/wwwroot/assets/img?ref=daveabrock.com">directory</a>, we can edit our <code>NavBar</code> component in our <code>Shared</code> directory to include our new file.</p><pre><code class="language-html">&lt;nav class="flex items-center justify-between flex-wrap bg-black p-6 my-bar"&gt;
    &lt;div class="flex items-center flex-shrink-0 text-white mr-6"&gt;
        &lt;img src="images/dotnet-bot-jetpack.png"&gt;
        &lt;span class="font-semibold text-xl tracking-tight"&gt;Blast Off with Blazor&lt;/span&gt;
    &lt;/div&gt;
    &lt;! -- more html left out for brevity --&gt;
&lt;/nav&gt;
</code></pre><p>I feel better and, as a bonus, the fine folks at NASA don’t have to worry about asking me to take their official logo down.</p><figure class="kg-card kg-image-card"><img src="https://www.daveabrock.com/content/images/2021/05/new-site-icon.png" class="kg-image" alt="Our title bar in action" loading="lazy" width="1312" height="832" srcset="https://www.daveabrock.com/content/images/size/w600/2021/05/new-site-icon.png 600w, https://www.daveabrock.com/content/images/size/w1000/2021/05/new-site-icon.png 1000w, https://www.daveabrock.com/content/images/2021/05/new-site-icon.png 1312w" sizes="(min-width: 720px) 720px"></figure><p>Now, we can head over the <a href="https://realfavicongenerator.net/?ref=daveabrock.com">RealFaviconGenerator</a> site to upload our new icon. After adjusting any settings to our liking, it’ll give us a bunch of icons, which we’ll unzip to the root of our <code>wwwroot</code> directory.</p><p>In <code>index.html</code> in the <code>wwwroot</code> directory, add the following inside the <code>&lt;head&gt;</code> tag:</p><pre><code class="language-html">&lt;link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon.png"&gt;
&lt;link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"&gt;
&lt;link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"&gt;
&lt;link rel="manifest" href="/site.webmanifest"&gt;
&lt;link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"&gt;
&lt;meta name="msapplication-TileColor" content="#da532c"&gt;
&lt;meta name="theme-color" content="#ffffff"&gt;
</code></pre><p>While it’s not the worst idea to put this markup in a component or partial view, I’m fine with putting it right into my static <code>index.html</code> file—it’s a one-time step and this is the only file that needs it.</p><h2 id="what-about-the-tests">What about the tests?</h2><p>I’ve placed an emphasis on <a href="https://daveabrock.com/2020/10/28/blast-off-blazor-404-page?ref=daveabrock.com#test-our-component-with-the-bunit-library">testing our components</a> with the bUnit library. We’ll work on testing this, and the rest of our <code>Index</code> component, in the next post. We need to mock a few things, like <code>HttpClient</code>, and I’m currently researching the best way to do so. Our next post will focus on testing Blazor components with <code>HttpClient</code> dependencies.</p><h2 id="wrap-up">Wrap up</h2><p>In this post, we dynamically updated the HTML head by setting the page title based on the image. Then, we updated our header icon and also showed how to include favicons in a Blazor WebAssembly project.</p><p>Stay tuned for the next post where we work on writing tests for our <code>Index</code> component.</p><h2 id="resources">Resources</h2><ul><li><a href="https://jonhilton.net/blazor-update-html-head/?ref=daveabrock.com">Update the HTML head from your Blazor components</a> (Jon Hilton)</li><li><a href="https://www.meziantou.net/dynamically-setting-the-page-title-in-a-blazor-application.htm?ref=daveabrock.com">Dynamically setting the page title in a Blazor application</a> (Gérald Barré)</li><li><a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-preview-8/?ref=daveabrock.com#influencing-the-html-head-in-blazor-apps">Influencing the HTML head in Blazor apps</a>(Daniel Roth)</li><li><a href="https://github.com/dotnet/aspnetcore/issues/10450?ref=daveabrock.com">Influencing HTML Head from a Blazor component</a> (GitHub issue)</li><li><a href="https://andrewlock.net/adding-favicons-to-your-asp-net-core-website-with-realfavicongenerator/?ref=daveabrock.com">Adding favicons to your ASP.NET Core website with Real Favicon Generator</a> (Andrew Lock)</li></ul> ]]></content:encoded>
    </item>

</channel>
</rss>