<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Khalid Abuhakmeh</title>
    <description>Khalid is a product designer, traveler, respected community member, and open source contributor.</description>
    <link>https://khalidabuhakmeh.com/</link>
    <atom:link href="https://khalidabuhakmeh.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 11 Apr 2026 15:06:54 +0000</pubDate>
    <lastBuildDate>Sat, 11 Apr 2026 15:06:54 +0000</lastBuildDate>
    <generator>Jekyll v4.3.3</generator>
    
      <item>
        <title>Server-Sent Events in ASP.NET Core and .NET 10</title>
        <description>&lt;p&gt;Like many .NET developers, I’m starting to look at the features coming in .NET 10, C# 14, and specifically ASP.NET Core. To my surprise, ASP.NET Core Minimal APIs now support Server-Sent Events (SSE). For folks who don’t know what Server-Sent Events are, they are a unidirectional channel from the server to a client where a client can subscribe to events. SSE is handy for building live news feeds, stock ticker applications, or any system that has real-time information.&lt;/p&gt;

&lt;p&gt;Inevitably, folks will ask, what’s the difference between SSE and SignalR? The difference is that SSE is lighter than WebSockets, and you can implement an SSE solution using the HTTP protocol. Whereas WebSockets, SignalR’s default operating mode, is a different protocol entirely. WebSockets are great, but the bidirectional communication between server and client adds additional costs that are typically unnecessary for the systems I mentioned previously.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to implement a straightforward SSE example using ASP.NET Core Minimal APIs, a background service, and some basic JavaScript.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-anatomy-of-a-sse-endpoint&quot;&gt;The Anatomy of a SSE Endpoint&lt;/h2&gt;

&lt;p&gt;Starting in .NET 10, you can now use the &lt;code&gt;TypedResults&lt;/code&gt; class to return a &lt;code&gt;ServerSentEventsResult&lt;/code&gt;, which takes an &lt;code&gt;IAsyncEnumerable&amp;lt;&amp;gt;&lt;/code&gt; instance and an event type.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel;
using System.Runtime.CompilerServices;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton&amp;lt;FoodService&amp;gt;();
builder.Services.AddHostedService&amp;lt;FoodServiceWorker&amp;gt;();

var app = builder.Build();
app.UseDefaultFiles().UseStaticFiles();

app.MapGet(&quot;/orders&quot;, (FoodService foods, CancellationToken token) =&amp;gt;
    TypedResults.ServerSentEvents(
        foods.GetCurrent(token),
        eventType: &quot;order&quot;)
);

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example code, the &lt;code&gt;foods.GetCurrent&lt;/code&gt; method call returns an &lt;code&gt;IAsyncEnumerable&lt;/code&gt; of food-based emojis. The cancellation token allows the client to unsubscribe, stopping the enumeration and server-side computation.&lt;/p&gt;

&lt;p&gt;That’s all you need; let’s see our &lt;code&gt;IAsyncEnumerable&lt;/code&gt; implementation.&lt;/p&gt;

&lt;h2 id=&quot;implementing-an-iasyncenumerable-food-service&quot;&gt;Implementing an IAsyncEnumerable Food Service&lt;/h2&gt;

&lt;p&gt;While implementing an &lt;code&gt;IAsyncEnumerable&lt;/code&gt; is straightforward, I wanted to write an implementation that synced all subscribers to a single source of truth. I accomplish this task in two classes: &lt;code&gt;FoodService&lt;/code&gt; and &lt;code&gt;FoodServiceWorker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FoodService&lt;/code&gt; implements an &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and allows all subscribers to sync to get a single food item’s &lt;code&gt;Current&lt;/code&gt; value.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class FoodService : INotifyPropertyChanged
{
    public FoodService()
    {
        Current = Foods[Random.Shared.Next(Foods.Length)];
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    private static readonly string[] Foods = [&quot;🍔&quot;, &quot;🍟&quot;, &quot;🥤&quot;, &quot;🍤&quot;, &quot;🍕&quot;, &quot;🌮&quot;, &quot;🥙&quot;];

    private string Current
    {
        get;
        set
        {
            field = value;
            OnPropertyChanged();
        }
    }

    public async IAsyncEnumerable&amp;lt;string&amp;gt; GetCurrent(
        [EnumeratorCancellation] CancellationToken ct)
    {
        while (ct is not { IsCancellationRequested: true })
        {
            yield return Current;
            var tcs = new TaskCompletionSource();
            PropertyChangedEventHandler handler = (_, _) =&amp;gt; tcs.SetResult();
            PropertyChanged += handler;
            try
            {
                await tcs.Task.WaitAsync(ct);
            }
            finally
            {
                PropertyChanged -= handler;
            }
        }
    }

    public void Set()
    {
        Current = Foods[Random.Shared.Next(Foods.Length)];
    }

    protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, I need a background service that updates the food choices at a timed interval.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class FoodServiceWorker(FoodService foodService)
    : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            foodService.Set();
            await Task.Delay(1000, stoppingToken);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s write the HTML subscribing to the SSE endpoint defined in my simple sample.&lt;/p&gt;

&lt;h2 id=&quot;subscribing-to-sse-using-javascript&quot;&gt;Subscribing to SSE using JavaScript&lt;/h2&gt;

&lt;p&gt;In a new &lt;code&gt;index.html&lt;/code&gt; file in &lt;code&gt;wwwroot&lt;/code&gt;, I’ll need to create a new EventSource object, listen for my &lt;code&gt;order&lt;/code&gt; events to come through, and handle them appropriately.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;style&amp;gt;
    ul {
        display: flex;
        flex-direction: row;
        list-style: none;
        flex-wrap: wrap;
        width: 90%;
        gap: 1rem;
        padding: 0;
    }

    li {
        font-size: 2rem;
    }
&amp;lt;/style&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;h1&amp;gt;Khalid&apos;s Fast-Food Fair&amp;lt;/h1&amp;gt;
&amp;lt;ul id=&quot;orders&quot;&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;script&amp;gt;
    const eventSource = new EventSource(&apos;/orders&apos;);
    const angelsList = document.getElementById(&apos;orders&apos;);

    eventSource.addEventListener(&apos;order&apos;, event =&amp;gt; {
        const li = document.createElement(&apos;li&apos;);
        li.textContent = event.data;
        angelsList.appendChild(li);
    });

    eventSource.onerror = error =&amp;gt; {
        console.error(&apos;EventSource failed:&apos;, error);
        eventSource.close();
    };
&amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s that simple. When the browser loads the page, we’ll immediately subscribe to the SSE endpoint and start receiving food emojis. If you open two pages, you’ll see the emojis synced between the pages.&lt;/p&gt;

&lt;p&gt;Try this quick sample, and let me know if you have any questions. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/server-sent-events-in-aspnet-core-and-dotnet-10</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/server-sent-events-in-aspnet-core-and-dotnet-10</guid>
        
        <category>dotnet,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Generic C# Methods with Enum Constraints for .NET</title>
        <description>&lt;p&gt;Every couple of years, I tend to write the same variation of an &lt;code&gt;enum&lt;/code&gt; helper that reads metadata from an enumeration using reflection. Almost any .NET developer with a few years of experience has done the same. The implementation uses Generics to work for any &lt;code&gt;enum&lt;/code&gt; defined in my solution, as there is typically more than one described in a typical .NET solution. Historically, generics and enums didn’t work well because of the limitations of generics when dealing with this particular type, but to my surprise, they do now!&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to write the helper method I’m describing while ensuring the generic constraints stop us from passing in arguments other than enums.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;straight-to-the-implementation&quot;&gt;Straight To The Implementation&lt;/h2&gt;

&lt;p&gt;Since this post will be short, I’ll start with a sample you can play with.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel;
using System.Reflection;

// get all descriptions
{
    Console.WriteLine(&quot;Groceries:\n&quot;);
    var descriptions = Enums.GetDescriptions&amp;lt;Groceries&amp;gt;();
    foreach (var (value, description) in descriptions)
    {
        Console.WriteLine($&quot;{value} - {description}&quot;);
    }
    Console.WriteLine();
}

// Get a description for a single value
{
    var (value, description) = Enums.GetDescription(Groceries.Fruit);
    Console.WriteLine($&quot;Single value:\n{value} - {description}&quot;);
}

public enum Groceries
{
    [Description(&quot;Apples, Oranges, Bananas&quot;)]
    Fruit,
    [Description(&quot;Spinach, Kale, Broccoli, Cabbage&quot;)]
    Vegetables,
    [Description(&quot;Cheese, Milk, Yogurt&quot;)]
    Dairy,
    [Description(&quot;Chicken, Beef, Pork, Lamb, Turkey&quot;)]
    Meat,
    [Description(&quot;Anything not listed above&quot;)]
    Other
}

public static class Enums
{
    public static IEnumerable&amp;lt;(TEnum Value, string Description)&amp;gt; GetDescriptions&amp;lt;TEnum&amp;gt;()
        where TEnum : struct, Enum
    {
        var values = Enum.GetValues&amp;lt;TEnum&amp;gt;();
        foreach (var value in values)
        {
            yield return GetDescription(value);
        }
    }

    public static (TEnum Value, string Description) GetDescription&amp;lt;TEnum&amp;gt;(TEnum value)
        where TEnum : struct, Enum
    {
        var type = typeof(TEnum);
        var name = value.ToString();
        var info = type.GetMember(name)[0];
        var description = info.GetCustomAttribute&amp;lt;DescriptionAttribute&amp;gt;() is { } attr
            ? attr.Description
            : name;
        
        return (value, description);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The helper code is here for people who don’t want to visualize the previous sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class Enums
{
    public static IEnumerable&amp;lt;(TEnum Value, string Description)&amp;gt; GetDescriptions&amp;lt;TEnum&amp;gt;()
        where TEnum : struct, Enum
    {
        var values = Enum.GetValues&amp;lt;TEnum&amp;gt;();
        foreach (var value in values)
        {
            yield return GetDescription(value);
        }
    }

    public static (TEnum Value, string Description) GetDescription&amp;lt;TEnum&amp;gt;(TEnum value)
        where TEnum : struct, Enum
    {
        var type = typeof(TEnum);
        var name = value.ToString();
        var info = type.GetMember(name)[0];
        var description = info.GetCustomAttribute&amp;lt;DescriptionAttribute&amp;gt;() is { } attr
            ? attr.Description
            : name;
        
        return (value, description);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The essential part of our generic methods is our method declarations’ &lt;code&gt;where&lt;/code&gt; clause.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;where TEnum: struct, Enum
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This line adds two crucial elements to our generic method.&lt;/p&gt;

&lt;p&gt;It makes sure that &lt;code&gt;TEnum&lt;/code&gt; is an &lt;code&gt;Enum&lt;/code&gt; type.
The &lt;code&gt;struct&lt;/code&gt; ensures that &lt;code&gt;TEnum&lt;/code&gt; is non-nullable.&lt;/p&gt;

&lt;p&gt;The non-nullability of an &lt;code&gt;Enum&lt;/code&gt; is essential since we are using the &lt;code&gt;Enum.GetValues&amp;lt;TEnum&amp;gt;&lt;/code&gt; method to get known values. You could remove this constraint, but your implementation would require more boxing and defensive programming in the form of null checks. It’s more straightforward to enforce the &lt;code&gt;struct&lt;/code&gt; requirement.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you go, a constrained generic method implementation that can get metadata from an Enum value. If you’re still wondering, “where would I use this?” I find these methods helpful in web applications for creating a &lt;code&gt;SelectListItem&lt;/code&gt;, but I stuck with Tuples for this post. What a time to be alive. Cheers!&lt;/p&gt;

</description>
        <pubDate>Tue, 04 Mar 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/generic-csharp-methods-with-enum-constraints-for-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/generic-csharp-methods-with-enum-constraints-for-dotnet</guid>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Strongly-Typed Markdown for ASP.NET Core Content Apps</title>
        <description>&lt;p&gt;Every development career has milestone moments. One we all likely share is building a custom content management system, or CMS, as developers like to refer to it. A common approach to melding metadata and content is utilizing the old reliable Markdown format, which fuses YAML frontmatter with a simple content format. While YAML is flexible, it can be less than ideal when wanting to use that embedded data in your ASP.NET Core applications.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you a quick experiment around processing Markdown files and their YAML into a strongly-type C# object. The example allows you to easily modify content while still having access to instances of data that you can strongly type.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-magnificent-markdown&quot;&gt;The Magnificent Markdown&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.markdownguide.org/&quot;&gt;Markdown&lt;/a&gt; is a very flexible format whose strength comes from its simplicity. Let’s examine a document that defines a person’s profile.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
name: &quot;Khalid Abuhakmeh&quot;
profession: &quot;Software Developer&quot;
hobbies: [&quot;video games&quot;, &quot;movies&quot;, &quot;boxing&quot;]
---

## Summary

I am writing a little about myself here and this should appear
in the page. Cool! Check me out at my [personal blog](https://khalidabuhakmeh.com).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The top of the document defines a data model with properties for &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Profession&lt;/code&gt;, and &lt;code&gt;Hobbies&lt;/code&gt;. The C# data model for this YAML  would consist of three properties.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Asset
{
    public string Name { get; set; } = &quot;&quot;;
    public string Profession { get; set; } = &quot;&quot;;
    public string[] Hobbies { get; set; } = [];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s build an object that will parse the Markdown file’s front matter while helping us render the content into HTML for use on a Razor page.&lt;/p&gt;

&lt;h2 id=&quot;the-markdownobject-and-parsing-files&quot;&gt;The MarkdownObject and Parsing Files&lt;/h2&gt;

&lt;p&gt;For my experiment, I created a &lt;code&gt;MarkdownObject&amp;lt;T&amp;gt;&lt;/code&gt; class that takes a content string and parses the document into its parts. The &lt;code&gt;T&lt;/code&gt; argument is up to the developer to determine.&lt;/p&gt;

&lt;p&gt;To continue with the code, you must add the &lt;code&gt;Markdig&lt;/code&gt; package and the &lt;code&gt;YamlDotNet&lt;/code&gt; package.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;PackageReference Include=&quot;Markdig&quot; Version=&quot;0.40.0&quot; /&amp;gt;
  &amp;lt;PackageReference Include=&quot;YamlDotNet&quot; Version=&quot;16.3.0&quot; /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s look at the implementation next.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Markdig;
using Markdig.Extensions.Yaml;
using Markdig.Syntax;
using Microsoft.AspNetCore.Html;
using YamlDotNet.Serialization;
using Md = Markdig.Markdown;

namespace SuperContent.Models;

public class MarkdownObject&amp;lt;T&amp;gt;
{
    private static readonly MarkdownPipeline MarkdownPipeline 
        = new MarkdownPipelineBuilder()
            .UseYamlFrontMatter()
            .UseAdvancedExtensions()
            .Build();
    private static readonly IDeserializer Deserializer 
        = new DeserializerBuilder()
            .WithYamlFormatter(new YamlFormatter())
            .WithCaseInsensitivePropertyMatching()
            .Build();

    public MarkdownObject(string content)
    {
        var doc = Md.Parse(content, MarkdownPipeline);
        FrontMatter = default;
        
        if (doc.Descendants&amp;lt;YamlFrontMatterBlock&amp;gt;().FirstOrDefault() is { } fm)
        {
            var yaml = fm.Lines.ToSlice();
            FrontMatter = Deserializer.Deserialize&amp;lt;T&amp;gt;(yaml.Text);
            
            // we don&apos;t want front matter after it&apos;s processed
            doc.Remove(fm);
        }
        
        // turn it into HTML once
        Html = new HtmlString(doc.ToHtml());
    }

    public T? FrontMatter { get; private set; }
    
    public IHtmlContent Html { get; private set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the case of this demo, we’ll create an instance of &lt;code&gt;MarkdownObject&amp;lt;Asset&amp;gt;&lt;/code&gt;. Let’s see how to use this type in a Razor Page.&lt;/p&gt;

&lt;h2 id=&quot;markdownobject-in-a-razor-page&quot;&gt;MarkdownObject in a Razor Page&lt;/h2&gt;

&lt;p&gt;In my demo, I have all my Markdown files in a &lt;code&gt;Data&lt;/code&gt; directory. Each file in the data directory has a unique file name that we’ll use in our Razor Page as a &lt;code&gt;slug&lt;/code&gt;. We’ll also use the Model to output the data and the processed HTML into a structured layout.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/profile/{slug}&quot;
@model SuperContent.Pages.Profile

&amp;lt;div class=&quot;row&quot;&amp;gt;
    &amp;lt;div class=&quot;col-12&quot;&amp;gt;
        &amp;lt;h1&amp;gt;@Model.Asset.FrontMatter?.Name&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div class=&quot;row&quot;&amp;gt;
    &amp;lt;div class=&quot;col-3&quot;&amp;gt;
        &amp;lt;dl&amp;gt;
            &amp;lt;dt&amp;gt;Profession&amp;lt;/dt&amp;gt;
            &amp;lt;dd&amp;gt;@Model.Asset.FrontMatter?.Profession&amp;lt;/dd&amp;gt;
            &amp;lt;dt&amp;gt;Hobbies&amp;lt;/dt&amp;gt;
            &amp;lt;dd&amp;gt;
                &amp;lt;ul&amp;gt;
                    @if (Model.Asset is { FrontMatter.Hobbies : { } hobbies })
                    {
                        @foreach (var hobby in hobbies)
                        {
                            &amp;lt;li&amp;gt;@hobby&amp;lt;/li&amp;gt;
                        }
                    }
                &amp;lt;/ul&amp;gt;
            &amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;col-9&quot;&amp;gt;
        @Model.Asset.Html
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, what does the page’s model look like?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SuperContent.Models;

namespace SuperContent.Pages;

public partial class Profile : PageModel
{
    [BindProperty(SupportsGet = true)]
    public string Slug { get; set; } = &quot;&quot;;
    
    public MarkdownObject&amp;lt;Asset&amp;gt; Asset { get; set; } 
        = null!;
    
    public IActionResult OnGet()
    {
        // read a file from the Data directory based on the slug
        // sanitize the slug first because people are mean
        var sanitizedSlug = SlugRegex.Replace(Slug, &quot;&quot;);
        var path = Path.Combine(&quot;Data&quot;, $&quot;{sanitizedSlug}.md&quot;);

        if (System.IO.File.Exists(path))
        {
            var content = System.IO.File.ReadAllText($&quot;Data/{sanitizedSlug}.md&quot;);
            Asset = new(content);
            return Page();
        }

        return NotFound();
    }

    [GeneratedRegex(&quot;[^a-zA-Z0-9_-]&quot;)]
    private static partial Regex SlugRegex { get; }
}

public class Asset
{
    public string Name { get; set; } = &quot;&quot;;
    public string Profession { get; set; } = &quot;&quot;;
    public string[] Hobbies { get; set; } = [];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;OnGet&lt;/code&gt; method contains some protective code to prevent access to other files, but it’s ultimately pretty straightforward. When you go to &lt;code&gt;/profile/Khalid,&lt;/code&gt; you’ll see a nicely formatted page that mixes data and content into predetermined HTML because we use the new &lt;code&gt;MarkdownObject&lt;/code&gt; class. Sweet!&lt;/p&gt;

&lt;p&gt;I’ve pushed the code to my &lt;a href=&quot;https://github.com/khalidabuhakmeh/SuperContent&quot;&gt;GitHub repository so you can try this sample&lt;/a&gt; for yourself. Please give it a try and let me know what you think. As always, thanks for reading and sharing my posts. Cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 25 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/strongly-typed-markdown-for-aspnet-core-content-apps</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/strongly-typed-markdown-for-aspnet-core-content-apps</guid>
        
        <category>aspnet,</category>
        
        <category>markdown</category>
        
        
      </item>
    
      <item>
        <title>The Curious Case of .NET ConcurrentDictionary and Closures</title>
        <description>&lt;p&gt;I was recently looking at the &lt;a href=&quot;https://duendesoftware.com&quot;&gt;Duende Software&lt;/a&gt; codebase, and I kept seeing the same suggestion offered by the IDE tooling whenever I encountered a &lt;code&gt;ConcurrentDictionary&lt;/code&gt;: &lt;strong&gt;“Closure can be eliminated: method has overload to avoid closure creation.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the suggestion appears in the tooling, there isn’t a quick fix action to apply the change. It left me scratching my head because there wasn’t an immediately obvious solution.&lt;/p&gt;

&lt;p&gt;This post will define closures and explain their problems. We’ll also explain how to change your usage of &lt;code&gt;ConcurrentDictionary&lt;/code&gt; to avoid closures altogether.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-are-closures&quot;&gt;What Are Closures?&lt;/h2&gt;

&lt;p&gt;If you’ve ever worked with an &lt;code&gt;Action&lt;/code&gt;, &lt;code&gt;Func&lt;/code&gt;, &lt;code&gt;delegate&lt;/code&gt;, or LINQ, then you’ve likely encountered a closure. A closure is a language mechanism that allows you to treat a function with &lt;strong&gt;free variables&lt;/strong&gt; as if it were an object instance you may pass, invoke, or use in another context from when you first created it. &lt;a href=&quot;https://www.simplethread.com/c-closures-explained/&quot;&gt;Justin Etheredge&lt;/a&gt; has a great article explaining closures in-depth, but it’s when you use a lambda with a state outside the current scope of the lambda.&lt;/p&gt;

&lt;p&gt;Let’s create a closure by capturing a variable in a straightforward example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;void SayHello(string name)
{
    var hello = () =&amp;gt;
    {
        // name is captured causing an allocation
        // and potential concurrency issues
        Console.WriteLine($&quot;Hello {name}&quot;);
    };
    hello();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the code above, the compiler needs to capture the &lt;code&gt;name&lt;/code&gt; parameter to ensure all future calls to our &lt;code&gt;hello&lt;/code&gt; lambda can execute. Capture can cause issues that may be difficult to predict until you execute your code.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Additional allocations are needed to capture a value and can have resource utilization implications.&lt;/li&gt;
  &lt;li&gt;A value captured from outside the closure scope may be alterable if it is a reference type. Unintended state change can lead to unpredictable behavior.&lt;/li&gt;
  &lt;li&gt;Long-lived references may lead to memory leaks in the long run.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To avoid capture, ensure all lambdas pass state required as arguments.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;void SayHello(string name)
{
    var hello = (string n) =&amp;gt;
    {
        Console.WriteLine($&quot;Hello {n}&quot;);
    };
    hello(name);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now that we understand the basics, let’s examine the &lt;code&gt;ConcurrentDictionary&lt;/code&gt; suggestion and see how we might fix it.&lt;/p&gt;

&lt;h2 id=&quot;concurrentdictionarygetoradd-and-closure-creation&quot;&gt;ConcurrentDictionary.GetOrAdd and Closure Creation&lt;/h2&gt;

&lt;p&gt;Let’s write a straightforward use of the &lt;code&gt;GetOrAdd&lt;/code&gt; method on &lt;code&gt;ConcurrentDictionary&lt;/code&gt; and see what the issue might be.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Collections.Concurrent;

ConcurrentDictionary&amp;lt;string, Item&amp;gt; concurrentDictionary 
    = new();

var key = &quot;khalid&quot;;
var value = &quot;awesome&quot;;

var result = concurrentDictionary.GetOrAdd(key, (k) =&amp;gt; {
    Console.WriteLine($&quot;Building {k}&quot;);
    return new Item(value, DateTime.Now);
});

Console.WriteLine(result);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at the code, what variable do you think is creating the unnecessary closure?&lt;/p&gt;

&lt;p&gt;If you guessed &lt;code&gt;value&lt;/code&gt;, then you would be correct!&lt;/p&gt;

&lt;p&gt;How do we fix the closure since our tooling now suggests that there is a solution to this issue?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Closure can be eliminated: method has overload 
to avoid closure creation.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Well, let’s refactor and see how our code changes. I’ll add parameter prefixes to make clear what is happening.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Collections.Concurrent;

ConcurrentDictionary&amp;lt;string, Item&amp;gt; concurrentDictionary = new();

var key = &quot;khalid&quot;;
var value = &quot;awesome&quot;;

var result = concurrentDictionary.GetOrAdd(
    key: key,
    valueFactory: (k, arg) =&amp;gt;
    {
        Console.WriteLine($&quot;Building {k}&quot;);
        return new Item(arg, DateTime.Now);
    },
    factoryArgument: value);

Console.WriteLine(result);

record Item(string Value, DateTime Time);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So there is an overload on &lt;code&gt;ConcurrentDictionary.GetOrAdd&lt;/code&gt; that takes three parameters:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The key to our value.&lt;/li&gt;
  &lt;li&gt;The lambda function responsible for creating our value when we do not find it.&lt;/li&gt;
  &lt;li&gt;A singular factory argument. You must wrap multiple arguments in a container class.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using this overload, we now avoid closures, reduce allocations, and avoid potentially nasty concurrency or memory leak issues.&lt;/p&gt;

&lt;p&gt;If you’re using &lt;code&gt;ConcurrentDictionary&lt;/code&gt; check to see if you’re using &lt;code&gt;GetOrAdd&lt;/code&gt; and see if you’re using the more efficient overload. Thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 18 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/the-curious-case-of-dotnet-concurrentdictionary-and-closures</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/the-curious-case-of-dotnet-concurrentdictionary-and-closures</guid>
        
        <category>dotnet</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>ASP.NET Core and Chunking HTTP Cookies</title>
        <description>&lt;p&gt;If you’ve spent time around web development or your grocery store’s baked goods aisle, you’ve probably dealt with &lt;strong&gt;cookies&lt;/strong&gt;. Let’s discuss the web kind today. A cookie is a header key-value pair that is set on the server using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie&quot;&gt;&lt;code&gt;Set-Cookie&lt;/code&gt;&lt;/a&gt; key, and a value of &lt;code&gt;&amp;lt;name&amp;gt;=&amp;lt;value&amp;gt;&lt;/code&gt;. Cookies persist on the client, where the client will send each cookie to the server on each subsequent request. It’s a simple way to persist state in the stateless web environment and avoid complex session management infrastructure. That said, cookies have limitations, mainly the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#data_storage&quot;&gt;&lt;strong&gt;4kb&lt;/strong&gt; size limit&lt;/a&gt; for each unique cookie. Size limits can be a serious problem for ASP.NET Core applications, which rely heavily on maintaining user session data in an encrypted and encoded cookie.&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at a sample I wrote that uses the same &lt;code&gt;ICookieManager&lt;/code&gt; abstraction that ASP.NET Core uses to chunk large cookies successfully.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-you-would-and-wouldnt-use-cookies&quot;&gt;Why You Would and Wouldn’t Use Cookies&lt;/h2&gt;

&lt;p&gt;As the introduction mentions, cookies are a straightforward mechanism for maintaining the state between HTTP requests as users interact with your application. Cookies can significantly simplify your backend implementation, as you can expect requests to contain most of the information required to process user-intended actions. Cookies may include user information such as an ID, a name, an email address, and more. The request/response lifecycle of cookies also makes it easy to debug issues when they inevitably occur, as you can view an HTTP request and its headers in most logging mechanisms. These are only a few advantages, but let’s discuss some disadvantages.&lt;/p&gt;

&lt;p&gt;While cookies are configurable, you can assume that, generally, the client will pass them along with each request to the server. The additional payload on each request can add unnecessary overhead to requests that don’t take advantage of the cookies. For example, any request for a file might still receive all set cookies even though the goal is to serve static content. That adds unnecessary ingress and resource utilization to your applications. Imagine a request with 10 cookies with a maxed-out cookie size on each. That’s an additional 40kb per request! And speaking of resource utilization, if cookies are chunked or encrypted, they first need to be reassembled and unencrypted before you can use them. Depending on your ASP.NET Core pipeline setup, this can unnecessarily add to your resource utilization, leading to increased memory and CPU usage.&lt;/p&gt;

&lt;p&gt;My description does not say you should or shouldn’t ever use cookies, but you should be mindful that they have an associated cost. Now, let’s get to some code to see how to set a simple cookie and then use the &lt;code&gt;ChunkingCookieManager&lt;/code&gt; to chunk larger cookies.&lt;/p&gt;

&lt;h2 id=&quot;setting-cookies-in-aspnet-core&quot;&gt;Setting Cookies in ASP.NET Core&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You can see the &lt;a href=&quot;https://github.com/khalidabuhakmeh/CookieMonster&quot;&gt;entire sample at this GitHub repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like most web-related abstractions, you can access cookies from the current &lt;code&gt;HttpContext&lt;/code&gt;. Using the current request’s context, let’s set a cookie on an HTTP response.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;ctx.Response.Cookies.Append(&quot;cookie_monster&quot;, &quot;nom nom nom&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our sample, we’ll be reading and rewriting a value with appended data.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/nom-nom&quot;, async ctx =&amp;gt;
{
    ctx.Response.Cookies.Append(&quot;cookie_monster&quot;,
        ctx.Request.Cookies.TryGetValue(&quot;cookie_monster&quot;, out var cookie)
            ? $&quot;{cookie}, {RandomString()}&quot;
            : $&quot;{RandomString()}&quot;);
    // more code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That was easy! But there’s an issue: our cookie will continue expanding until it reaches our 4kb limit. Oh no! Admittedly, this is an example designed to fail quickly, but it’s easy to find yourself in a situation where cookies slowly creep up to the size limit. Let’s fix this code.&lt;/p&gt;

&lt;p&gt;Install the &lt;code&gt;Microsoft.AspNetCore.Authentication.Cookies&lt;/code&gt; NuGet package into your existing project to start using cookie chunking. In most cases, you’ll likely already have this dependency due to a transitive inclusion, but it never hurts to include it explicitly.&lt;/p&gt;

&lt;p&gt;Next, we’ll need to register the &lt;code&gt;ChunkingCookieManager&lt;/code&gt; in our services collection as an implementation of &lt;code&gt;ICookieManager&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddScoped&amp;lt;ICookieManager&amp;gt;(svc =&amp;gt; new ChunkingCookieManager
{
    // characters, not bytes... 🤔
    ChunkSize = 1000, ThrowForPartialCookies = true
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In my case, I reduced the chunk size for a few reasons.&lt;/p&gt;

&lt;p&gt;See the chunking behavior sooner than later.
The &lt;code&gt;ChunkSize&lt;/code&gt; is based on characters in .NET and not kilobytes, so you’ll need to account for that based on the data you’ll be storing.
&lt;code&gt;1000&lt;/code&gt; is a nice round number, but the default is &lt;code&gt;4050&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s look at the implementation in another minimal API endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;{
app.MapGet(&quot;/chunks&quot;, async (HttpContext ctx, ICookieManager cookieManager) =&amp;gt;
{
    var value = cookieManager.GetRequestCookie(ctx, &quot;chunky_monster&quot;) is { } cookie
        ? $&quot;{cookie}, {RandomString()}&quot;
        : $&quot;{RandomString()}&quot;;

    cookieManager.AppendResponseCookie(ctx, &quot;chunky_monster&quot;, value, new CookieOptions());

    // more code...
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a few essential elements to getting cookie chunking working:&lt;/p&gt;

&lt;p&gt;You must use the &lt;code&gt;ICookieManager&lt;/code&gt; implementation for all interactions of your logical cookie since it will take care of the chunks. Interacting with the cookies directly through the &lt;code&gt;HttpContext&lt;/code&gt; will cause you issues.
The &lt;code&gt;ICookieManager&lt;/code&gt; API requires access to an &lt;code&gt;HttpContext&lt;/code&gt; instance. There is no assumption that a cookie manager will have an HTTP context dependency injected. You could easily create an implementation that wraps this into a new API.
The &lt;code&gt;CookieOptions&lt;/code&gt; argument is required but can be left empty. Options allow you to set cookie options on the resulting cookie chunks, such as &lt;code&gt;Domain&lt;/code&gt;, &lt;code&gt;Expires&lt;/code&gt;, &lt;code&gt;Secure&lt;/code&gt;, and more.&lt;/p&gt;

&lt;p&gt;As the concrete type name suggests, we will be chunking cookies, meaning that if a cookie’s contents exceed our configured limits, we’ll produce multiple header values.&lt;/p&gt;

&lt;p&gt;You’ll usually see the following behavior in your browser’s dev tools.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Value&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;chunky_monster&lt;/td&gt;
      &lt;td&gt;chunks-2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;chunky_monsterC1&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;value chunk up to &lt;code&gt;ChunkSize&lt;/code&gt;&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;chunky_monsterC2&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;rest of value&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;chunky_monsterCN&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;more to come if necessary&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;There you go, you’ve successfully chunked your cookies using the mechanisms provided by ASP.NET Core.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Cookies are a bedrock of web development, but you need to be mindful of their benefits and drawbacks. If you do find yourself exceeding the size limits of cookies, I’d recommend first understanding why it has occurred and if you have room to optimize your data. In a pinch, adopting chunking can help you get over the sizing issue, but can have the drawbacks mentioned in one of the previous sections. If you think you have a better strategy, you can implement the &lt;code&gt;ICookieManager&lt;/code&gt; yourself and take a completely different approach. If you do, drop me a message and send me a link to your implementation.&lt;/p&gt;

&lt;p&gt;To &lt;a href=&quot;https://github.com/khalidabuhakmeh/CookieMonster&quot;&gt;try this sample out for yourself, head to my GitHub repository&lt;/a&gt;. As always, thanks for reading and sharing my posts.&lt;/p&gt;
</description>
        <pubDate>Tue, 11 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/aspnet-core-and-chunking-http-cookies</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/aspnet-core-and-chunking-http-cookies</guid>
        
        <category>aspnet,</category>
        
        <category>http</category>
        
        
      </item>
    
      <item>
        <title>Vogen and Value Objects with C# and .NET</title>
        <description>&lt;p&gt;When it comes to programming, correctness is the name of the game. Every developer aims to understand, model, and limit potential outliers when executing code because those unknown variables can lead to exceptions and critical failures. There are many techniques developers use, but I recently discovered a new library (at least to me) in the .NET community that aims to help developers constrain potential inputs using value objects.&lt;/p&gt;

&lt;p&gt;In this post, we’ll write a quick sample using Vogen to demonstrate how value objects can make our code clearer and less error-prone.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-a-value-object&quot;&gt;What is a Value Object?&lt;/h2&gt;

&lt;p&gt;A value object represents a logical concept but is a .NET primitive value such as &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, and more. A straightforward example might be a birth date. Most developers would define a birth date using the &lt;code&gt;DateTime&lt;/code&gt; type, hoping that the variable name clarifies the value’s intention.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;DateTime birthDate = new DateTime(1990, 1, 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The drawback to this code is nothing stops a developer from unintentionally using the &lt;code&gt;birthDate&lt;/code&gt; variable incorrectly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;DateTime birthDate = new DateTime(1990, 1, 1);
SetMovieReleaseDate(birthDate);
void SetMovieReleaseDate(DateTime date) { }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While the code technically works, it may not be what the developers intended logically. The birth date may or may not be the release date of a movie, and it’s difficult to tell if this code is “correct.” Let’s fix it using value objects.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var birthDate = new BirthDateTime(new (1990, 1, 1));
var movieReleaseDate = new MovieReleaseDateTime(birthDate.Value);
SetMovieReleaseDate(movieReleaseDate);

void SetMovieReleaseDate(MovieReleaseDateTime date) { }
// value objects
public record MovieReleaseDateTime(DateTime Value);
public record BirthDateTime(DateTime Value);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at this code, you can see that the developer intended to set a movie release date to the same value as the birth date. The goal is to minimize the chance of autocompleting your way into logical bugs that may be difficult to track down.&lt;/p&gt;

&lt;p&gt;Yes, this can seem overly ceremonious, so consider the benefits and drawbacks before deciding if you want to adopt it.&lt;/p&gt;

&lt;p&gt;Now, let’s see what Vogen is about.&lt;/p&gt;

&lt;h2 id=&quot;what-is-vogen&quot;&gt;What is Vogen?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://stevedunn.github.io/Vogen/overview.html&quot;&gt;Vogen&lt;/a&gt; is a NuGet library that utilizes source generators to generate value objects, taking much of the ceremony out of model creation. The library creates factory methods, comparisons, validation, and serializers on partial &lt;code&gt;struct&lt;/code&gt; and &lt;code&gt;class&lt;/code&gt; implementations.&lt;/p&gt;

&lt;p&gt;Let’s start by adding Vogen to a .NET console application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PackageReference Include=&quot;Vogen&quot; Version=&quot;7.0.0-beta.1&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In my example, I’ll create a &lt;code&gt;PacMan&lt;/code&gt; class that requires a &lt;code&gt;FavoriteGhost&lt;/code&gt; property to have a valid value of &lt;code&gt;Ghost&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class PacMan
{
    public Ghost FavoriteGhost { get; set; }

    public override string ToString()
    {
        return $&quot;Pac Man&apos;s favorite ghost is {FavoriteGhost}.&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our value object will be &lt;code&gt;Ghost&lt;/code&gt;; everyone knows that the ghosts that haunt Pac-Man include Blinky, Pinky, Inky, and Clyde. Let’s start with the unconstrained approach using Vogen.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[ValueObject&amp;lt;string&amp;gt;]
[Instance(&quot;Blinky&quot;, &quot;Blinky&quot;)]
[Instance(&quot;Pinky&quot;, &quot;Pinky&quot;)]
[Instance(&quot;Inky&quot;, &quot;Inky&quot;)]
[Instance(&quot;Clyde&quot;, &quot;Clyde&quot;)]
public partial struct Ghost;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the source generators have run, you’ll now have &lt;code&gt;public static readonly&lt;/code&gt; instances of each ghost on the &lt;code&gt;Ghost&lt;/code&gt; struct, allowing our code to run and set the &lt;code&gt;FavoriteGhost&lt;/code&gt; property on our &lt;code&gt;pacMan&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;You can create any &lt;code&gt;Ghost&lt;/code&gt; you like using the &lt;code&gt;From&lt;/code&gt; method on the struct.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var aNewGhost = Ghost.From(&quot;Khalid&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If your value objects are unconstrained, this might be a good time to stop, but we want to limit our &lt;code&gt;Ghost&lt;/code&gt; values. Let’s rework our &lt;code&gt;Ghost&lt;/code&gt; struct.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[ValueObject&amp;lt;string&amp;gt;]
public partial struct Ghost
{
    public static readonly Ghost Blinky = new(&quot;Blinky&quot;);
    public static readonly Ghost Pinky = new(&quot;Pinky&quot;);
    public static readonly Ghost Inky = new(&quot;Inky&quot;);
    public static readonly Ghost Clyde = new(&quot;Clyde&quot;);

    public static IReadOnlyCollection&amp;lt;Ghost&amp;gt; All { get; }
        = new[] { Blinky, Pinky, Inky, Clyde }.AsReadOnly();

    private static Validation Validate(string input) =&amp;gt;
        All.Any(g =&amp;gt; g.Equals(input))
            ? Validation.Ok
            : Validation.Invalid($&quot;Ghost must be {string.Join(&quot;, &quot;, All)}&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With some extra code, we can now validate that all values used to create a &lt;code&gt;Ghost&lt;/code&gt; fit within a defined set of values.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// will throw an exception
var aNewGhost = Ghost.From(&quot;Khalid&quot;);
// will pass
var aKnownGhost = Ghost.From(&quot;Blinky&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see the use of Vogen in a complete C# sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Vogen;

var pacMan = new PacMan
{
    FavoriteGhost = Ghost.Blinky
};

foreach (var ghost in Ghost.All)
{
    Console.WriteLine(ghost);
}

Console.WriteLine(pacMan);

[ValueObject&amp;lt;string&amp;gt;]
public partial struct Ghost
{
    public static readonly Ghost Blinky = new(&quot;Blinky&quot;);
    public static readonly Ghost Pinky = new(&quot;Pinky&quot;);
    public static readonly Ghost Inky = new(&quot;Inky&quot;);
    public static readonly Ghost Clyde = new(&quot;Clyde&quot;);

    public static IReadOnlyCollection&amp;lt;Ghost&amp;gt; All { get; }
        = new[] { Blinky, Pinky, Inky, Clyde }.AsReadOnly();

    private static Validation Validate(string input) =&amp;gt;
        All.Any(g =&amp;gt; g.Equals(input))
            ? Validation.Ok
            : Validation.Invalid($&quot;Ghost must be {string.Join(&quot;, &quot;, All)}&quot;);
}

public class PacMan
{
    public Ghost FavoriteGhost { get; set; }

    public override string ToString()
    {
        return $&quot;Pac Man&apos;s favorite ghost is {FavoriteGhost}.&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Using value objects is an efficient way to constrain inputs and outputs logically. It helps you reflect logical constraints in the codebase and offers readability levels that could be lost using primitive types. With the addition of Vogen, you can remove boilerplate code and get straight to using value objects, with the benefits of quickly accessing the underlying primitive value through explicit and implicit means.&lt;/p&gt;

&lt;p&gt;I think the next step for folks is likely to take an existing part of a codebase and see if converting it to use value objects improves readability and correctness.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post. As always, thanks for reading and sharing my posts.&lt;/p&gt;

</description>
        <pubDate>Tue, 04 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/vogen-and-value-objects-with-csharp-and-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/vogen-and-value-objects-with-csharp-and-dotnet</guid>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Initialize ASP.NET Core TagHelpers with Shared Data</title>
        <description>&lt;p&gt;ASP.NET Core has a superpower that few other frameworks have, largely thanks to the Razor engine. Razor syntax is a mix of HTML and C#, and most Razor syntax implementations will skew heavily towards HTML over C#. However, C# syntax offers the most value in control flow mechanics using if, for, and switch statements. Razor’s power is that
&lt;em&gt;even
HTML&lt;/em&gt; syntax is processed by C# and converted into compiled artifacts. This gives Razor a unique opportunity to do some amazing tricks.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to use the TagHelpers infrastructure to initialize all tag helper usage across your application and inject necessary shared data.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-taghelper-in-question&quot;&gt;The TagHelper In Question&lt;/h2&gt;

&lt;p&gt;Let’s start by writing a simple tag helper that will replace the contents of a &lt;code&gt;span&lt;/code&gt; tag when a
&lt;code&gt;text&lt;/code&gt; attribute is set.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace WebApplication2.Models;

[HtmlTargetElement(&quot;span&quot;)]
public class MyTagHelper: TagHelper
{
    [HtmlAttributeName(&quot;text&quot;)]
    public string Text { get; set; } = &quot;&quot;;

    [HtmlAttributeNotBound] 
    public string Version { get; set; } = &quot;&quot;;
    
    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        output.Content.SetHtmlContent(Text);
        output.Attributes.Add(&quot;data-version&quot;, Version);
        return Task.CompletedTask;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage of this tag helper is straightforward. In a Razor view, add the following tag.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;span class=&quot;fs-1 d-block&quot; text=&quot;Hello, World!&quot;&amp;gt;...&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;fs-1 d-block&quot;&amp;gt;&amp;lt;/span&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you may have noticed in the &lt;code&gt;MyTagHelper&lt;/code&gt; implementation, there is another property of
&lt;code&gt;Version&lt;/code&gt;, which I decorated with the
&lt;code&gt;HtmlAttributeNotBound&lt;/code&gt; attribute. This value will be initialized with the tag helper initialization infrastructure.&lt;/p&gt;

&lt;h2 id=&quot;taghelper-initializers&quot;&gt;TagHelper Initializers&lt;/h2&gt;

&lt;p&gt;We’ll implement the &lt;code&gt;ITagHelperInitializer&lt;/code&gt; generic interface, which has an
&lt;code&gt;Initialize&lt;/code&gt; method that takes an instance of a tag helper and a &lt;code&gt;ViewContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class MyTagHelperInitializer(string defaultText, string version) 
    : ITagHelperInitializer&amp;lt;MyTagHelper&amp;gt;
{
    public void Initialize(MyTagHelper helper, ViewContext context)
    {
        helper.Text = defaultText;
        helper.Version = version;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, the data passed into our implementation can be used to hydrate all tag helpers of
&lt;code&gt;MyTagHelper&lt;/code&gt;. This is awesome for multiple reasons.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Expensive data can be calculated once and set globally, reducing resource utilization and speeding up page rendering.&lt;/li&gt;
  &lt;li&gt;We have access to the
&lt;code&gt;ViewContext&lt;/code&gt;, so we can modify and enhance all request/response lifecycle elements if necessary.&lt;/li&gt;
  &lt;li&gt;We have direct access to the tag helper, so the initialization code is as straightforward as possible.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;ViewContext&lt;/code&gt; gives us access to
&lt;code&gt;HttpContext&lt;/code&gt;, so we can also handle request-specific values from cookies, user information, etc.&lt;/li&gt;
  &lt;li&gt;Also, we can request other services that are already registered in our services collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do we use this initializer? In
&lt;code&gt;Program&lt;/code&gt;, add the following line to register our initializer with our services collection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddSingleton&amp;lt;
    ITagHelperInitializer&amp;lt;MyTagHelper&amp;gt;
&amp;gt;(new MyTagHelperInitializer(&quot;Default Text&quot;, &quot;1.0.0&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our case, we’re passing in the initial values. However, this type could also take in application configuration and read values from the
&lt;code&gt;IConfiguration&lt;/code&gt; implementation of an ASP.NET Core application. It’s important to note that this type is registered as a
**Singleton
**, which means any data passed to it in the constructor is the data for the rest of the application’s lifetime.&lt;/p&gt;

&lt;p&gt;When we run our application, the tag helper will result in the following HTML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;span class=&quot;fs-1 d-block&quot; data-version=&quot;1.0.0&quot;&amp;gt;Hello, World!&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;fs-1 d-block&quot; data-version=&quot;1.0.0&quot;&amp;gt;Default Text&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow, so easy!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Part of building web experiences is handling requests efficiently and returning responses as quickly as possible. With tag helpers, you can help create more buffer space in your performance budgets by reducing and isolating the work needed to process data for HTML tags. Additionally, this technique of global initialization might also be helpful for test-driven UI tests, as attributes and their data can be added or removed depending on build flags. This approach is exciting, and I hope you try it in your applications.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my blog posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 14 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/initialize-aspnet-core-taghelpers-with-shared-data</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/initialize-aspnet-core-taghelpers-with-shared-data</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Writing a String Numeric Comparer with .NET 9</title>
        <description>&lt;p&gt;I recently saw that .NET 10 adds a numeric comparer, allowing you to sort string elements that may contain numeric values at the end of a string. Think movie sequels or number versions of an operating system. To my surprise, I could not believe it wasn’t already included in .NET, but then I sat down to try to write my own, and I now “get it”. The edge cases alone can drive you mad. Numeric ordering is subjective. Should the numbers come before Roman numerals? Should Roman numerals be parsed as numbers? What about decimals?&lt;/p&gt;

&lt;p&gt;Anyway, I’ve added my numeric comparer implementation in this post, which uses some of the latest .NET features. Enjoy!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;a-list-of-numbered-things&quot;&gt;A List of Numbered Things&lt;/h2&gt;

&lt;p&gt;A number at the end of a text is typical for movies, books, video games, and products. These numbers denote a newer and better iteration of an item. For example, I have a combination of movies, Windows versions, and some decimal values.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var numberedThings = new List&amp;lt;string&amp;gt;
{
    &quot;Godfather&quot;, &quot;Godfather 3&quot;, &quot;Scream&quot;,
    &quot;Scream 2&quot;, &quot;Scream 3&quot;, &quot;Scream 1&quot;,
    &quot;Windows 10&quot;, &quot;Windows 7&quot;,
    &quot;Windows 11&quot;, &quot;Rocky 5&quot;,
    &quot;Rocky 2&quot;, &quot;Rocky 4&quot;, &quot;Rocky 3&quot;, &quot;Rock&quot;,
    &quot;1.2&quot;, &quot;1.3&quot;, &quot;1.1&quot;, &quot;Rocky&quot;, &quot;Windows XP&quot;, 
    &quot;Godfather 2&quot;, &quot;1.11&quot;, &quot;1.10&quot;, &quot;10.0&quot;, &quot;1.0&quot;
};

var numericOrderer = new NumericOrderer();
var sorted = numberedThings
    .OrderBy(x =&amp;gt; x, numericOrderer)
    .ToList();

foreach (var item in sorted)
{
    Console.WriteLine(item);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The goal is to have the output result in alphanumeric ordering. For example, &lt;code&gt;Godfather&lt;/code&gt; should come before
&lt;code&gt;Godfather 2&lt;/code&gt;. Also, when it comes to strings made of numbers, I want each part of a value to be treated as a whole number. For example,
&lt;code&gt;1.1&lt;/code&gt;, &lt;code&gt;1.10&lt;/code&gt;, and &lt;code&gt;1.11&lt;/code&gt; would follow that order.&lt;/p&gt;

&lt;p&gt;We expect the following output from the previous code based on the input.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1.0
1.1
1.2
1.3
1.10
1.11
10.0
Godfather
Godfather 2
Godfather 3
Rock
Rocky
Rocky 2
Rocky 3
Rocky 4
Rocky 5
Scream
Scream 1
Scream 2
Scream 3
Windows 7
Windows 10
Windows 11
Windows XP
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s look at my implementation.&lt;/p&gt;

&lt;h2 id=&quot;writing-a-numericorderer-with-spans&quot;&gt;Writing a NumericOrderer with Spans&lt;/h2&gt;

&lt;p&gt;Here is my &lt;code&gt;NumericOrderer&lt;/code&gt; based on the collection of data previously mentioned.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public sealed class NumericOrderer : IComparer&amp;lt;string&amp;gt;
{
    public int Compare(string? x, string? y)
    {
        if (x == null &amp;amp;&amp;amp; y == null) return 0;
        if (x == null) return -1;
        if (y == null) return 1;

        var xSpan = x.AsSpan();
        var ySpan = y.AsSpan();
        
        var commonPrefixLength = xSpan.CommonPrefixLength(ySpan);

        while (commonPrefixLength &amp;gt; 0)
        {
            xSpan = xSpan[commonPrefixLength..];
            ySpan = ySpan[commonPrefixLength..];
            commonPrefixLength = xSpan.CommonPrefixLength(ySpan);
        }
        
        if (int.TryParse(xSpan, out var xNumber) &amp;amp;&amp;amp; 
            int.TryParse(ySpan, out var yNumber))
        {
            return xNumber.CompareTo(yNumber);
        }

        return xSpan.CompareTo(ySpan, StringComparison.Ordinal);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are three configuration points you should consider in this implementation.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;CommonPrefixLength&lt;/code&gt; can also take a &lt;code&gt;Comparer&lt;/code&gt; argument, which might help ignore casing.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;CompareTo&lt;/code&gt; method currently takes a
&lt;code&gt;StringComparison.Ordinal&lt;/code&gt; value, which is case sensitive. I suggest changing this based on your needs.&lt;/li&gt;
  &lt;li&gt;The use of &lt;code&gt;int.TryParse&lt;/code&gt; compares whole numbers. If your values contain decimals, then you may want to try
&lt;code&gt;double.TryParse&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are there edge cases here? Very likely, but when ordering anything with “opinions”, you’ll likely have to tweak it to your liking. As I mentioned previously, Roman numerals are commonly used in place of Arabic numerals, so you may want to tweak this to support those, or you may want
&lt;code&gt;Windows XP&lt;/code&gt; to appear before &lt;code&gt;Windows 11&lt;/code&gt; in a list. You’re the sorting wizard in your magical journey.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This exercise made me realize that building a general-purpose numeric orderer is likely a herculean task. Instead, I’d probably implement a sorter based on your needs for that specific use case. Also, I learned that the
&lt;code&gt;Span&lt;/code&gt; APIs are very good and capable of breaking apart strings without creating new instances in memory. Finally, while this comparison works well for a single-point dataset, you’re likely dealing with more complex data models with other sortable fields that can be more accurately sorted (think numbers and dates). I’d likely lean more on predictably sortable values in a production setting than leaving it all to a general-purpose numeric comparer.&lt;/p&gt;

&lt;p&gt;At the very least, I hope this implementation gives you a starting point for writing and tweaking your implementation. As always, thanks for reading, and cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/writing-a-string-numeric-comparer-with-dotnet-9</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/writing-a-string-numeric-comparer-with-dotnet-9</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Great .NET Documentation with Astro, Starlight, and MarkdownSnippets</title>
        <description>&lt;p&gt;The hallmark of every great project is equally great documentation, but it can be increasingly difficult for developers to keep both in sync. Luckily, I’ve been experimenting again with a combination of Starlight and MarkdownSnippets to make maintaining code samples and documentation much more convenient.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to set up your repository so that MarkdownSnippets pulls samples from your codebase and updates your Starlight documentation.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;directory-structure-and-tools&quot;&gt;Directory Structure and Tools&lt;/h2&gt;

&lt;p&gt;To get started, let’s set up our repository for success. Let’s begin with folders. We’ll want to create the following folders at the root of a newly created directory.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- docs
- src
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;docs&lt;/code&gt; directory will hold our documentation powered by Starlight, and the
&lt;code&gt;src&lt;/code&gt; directory will have all our .NET code.&lt;/p&gt;

&lt;p&gt;We’ll want to run the following dotnet commands within the same directory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet new tool-manifest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s install the MarkdownSnippets tool.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet tool install MarkdownSnippets.Tool
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, let’s create the MarkdownSnippets configuration file of
&lt;code&gt;mdsnippets.json&lt;/code&gt;, which will tune our snippet generation to work with Starlight.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;$schema&quot;: &quot;https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/refs/heads/main/schema.json&quot;,
  &quot;Convention&quot;: &quot;InPlaceOverwrite&quot;,
  &quot;WriteHeader&quot;: false,
  &quot;ReadOnly&quot;: false,
  &quot;LinkFormat&quot;: &quot;None&quot;,
  &quot;OmitSnippetLinks&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Following the steps correctly, you’ll have the following files and folders.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- docs
- src
- .config
- mdsnippets.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Great! Let’s write some .NET code in our &lt;code&gt;src&lt;/code&gt; directory now.&lt;/p&gt;

&lt;h2 id=&quot;our-net-code-samples&quot;&gt;Our .NET Code Samples&lt;/h2&gt;

&lt;p&gt;Change to the &lt;code&gt;src&lt;/code&gt; directory and create a new
&lt;code&gt;Console&lt;/code&gt; application. Any will do. What’s important is using the MarkdownSnippets convention to develop a block of code to be extracted. Here’s the one I’m using in
&lt;code&gt;Program.cs&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// begin-snippet: App:HelloWorld
// Program.cs
Console.WriteLine(&quot;Hello, Again!&quot;);
// end-snippet
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it! Write and decorate as many code samples as you’ll use in the next section.&lt;/p&gt;

&lt;h2 id=&quot;our-starlight-documentation&quot;&gt;Our Starlight Documentation&lt;/h2&gt;

&lt;p&gt;Now, let’s move into the &lt;code&gt;docs&lt;/code&gt; directory and run the following command. Note you’ll need both Node and Yarn installed.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;yarn create astro --template starlight
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here, follow the Astro wizard to create a new documentation site. From the root, your directory structure should look similar to the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;- docs
	- .astro
	- .vscode
	- .yarn
	- src
	- public
	- astro.config.mjs
	- package.json
	- ...
- src
	- App
		- bin
		- obj
		- App.csproj
		- Program.cs
- mdsnippets.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s update our &lt;code&gt;package.json&lt;/code&gt; to scan our C# project, find snippets, and update our documentation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;type&quot;: &quot;module&quot;,
  &quot;version&quot;: &quot;0.0.1&quot;,
  &quot;scripts&quot;: {
    &quot;mdsnippets&quot;: &quot;cd .. &amp;amp;&amp;amp; dotnet mdsnippets&quot;,
    &quot;dev&quot;: &quot;npm run mdsnippets &amp;amp;&amp;amp; astro dev&quot;,
    &quot;start&quot;: &quot;npm run dev&quot;,
    &quot;build&quot;: &quot;npm run mdsnippets &amp;amp;&amp;amp; astro build&quot;
  },
  &quot;dependencies&quot;: {
    &quot;@astrojs/starlight&quot;: &quot;^0.29.3&quot;,
    &quot;astro&quot;: &quot;^4.16.10&quot;,
    &quot;sharp&quot;: &quot;^0.32.5&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Feel free to add or remove any additional scripts or dependencies for your particular use case. This is the bare minimum for this post.&lt;/p&gt;

&lt;p&gt;Now, let’s write some documentation. Find the &lt;code&gt;example.md&lt;/code&gt; file under
&lt;code&gt;docs/src/content/docs/guides/&lt;/code&gt; and write the following markdown.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
title: Hello, World!
description: Creating your first .NET Console Application
---

## Getting Started

Your first .NET application will be a console application, or what the cool folks like to call it, an app. Create a new project using the
`dotnet` CLI command `new`.

```bash title=&quot;Terminal&quot;
dotnet new console -o HelloWorld &amp;amp;&amp;amp; cd ./HelloWorld
```

Then, add the following code in the `Program.cs` file.

snippet: App:HelloWorld

Then run the app by using the following command.

```bash title=&quot;Terminal&quot;
dotnet run
```

Congratulations!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, run the &lt;code&gt;dev&lt;/code&gt; command from the root directory. MarkdownSnippets will transform the
&lt;code&gt;snippet: App:HelloWorld&lt;/code&gt; in your Markdown to the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
title: Hello, World!
description: Creating your first .NET Console Application
---

## Getting Started

Your first .NET application will be a console application, or what the cool folks like to call it, an app. Create a new project using the
`dotnet` CLI command `new`.

```bash title=&quot;Terminal&quot;
dotnet new console -o HelloWorld &amp;amp;&amp;amp; cd ./HelloWorld
```

Then, add the following code in the `Program.cs` file.

&amp;lt;!-- snippet: App:HelloWorld --&amp;gt;

```cs
// Program.cs
Console.WriteLine(&quot;Hello, Again!&quot;);
```

&amp;lt;!-- endSnippet --&amp;gt;

Then run the app by using the following command.

```bash title=&quot;Terminal&quot;
dotnet run
```

Congratulations!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can change the code in &lt;code&gt;Program.cs&lt;/code&gt; and rerun the command to see the documentation update.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you’re working on code-heavy documentation where samples speak louder than words, then combining MarkdownSnippets with Starlight is a great pairing. You’ll want to develop a good naming convention to make finding and altering samples easier, after which you’ll be sure that any code samples are valid, compiled, and run. After all, as developers, we all want to get it right the first time.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading, and cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 31 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/great-dotnet-documentation-with-astro-starlight-and-markdownsnippets</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/great-dotnet-documentation-with-astro-starlight-and-markdownsnippets</guid>
        
        <category>astro</category>
        
        <category>javascript</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Alpine.Js Polling ASP.NET Core APIs For Updates</title>
        <description>&lt;p&gt;Building dynamic JavaScript experiences has come a long in the 20 years since I first started software development, but updating the document object model (DOM) can still be a real pain in the butt. That’s why we’ve seen single-page application frameworks explode in use. While JavaScript provides a very capable API when interacting with the DOM, it can be verbose.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to use the Alpine.Js library’s declarative attribute approach to create a real-time updating UI with minimal JavaScript and no direct use of the DOM APIs.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-strength-of-alpinejs&quot;&gt;The Strength of Alpine.js&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://alpinejs.dev/&quot;&gt;Alpine.js&lt;/a&gt; is a lightweight JavaScript framework that allows you to compose behavior directly in your HTML markup. The library consists of 15 attributes, six properties, and two methods. While its surface API is small, what it offers is, as the site says,
&lt;strong&gt;“powerful as hell.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The strength of Alpine.js comes from its data model, which uses reactivity to detect changes to data and update the UI elements accordingly. Reactivity means you can update values naturally without keeping track of a dependency graph. Let’s take a look at a quick example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;div x-data=&quot;{ count: 0 }&quot;&amp;gt;
    &amp;lt;button x-on:click=&quot;count++&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;

    &amp;lt;span x-text=&quot;count&quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, the &lt;code&gt;count&lt;/code&gt; value is reactive. When you click the button, the value increments. Since the
&lt;code&gt;count&lt;/code&gt; value is also used in the &lt;code&gt;span&lt;/code&gt; element, it is updated at the time of the change. So easy!&lt;/p&gt;

&lt;p&gt;Values can also be accessed from JavaScript. With a few modifications, we can use the
&lt;code&gt;data&lt;/code&gt; method to create a shared context for our counter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;div x-data=&quot;count&quot;&amp;gt;
    &amp;lt;button x-on:click=&quot;increment()&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;
    &amp;lt;span x-text=&quot;value&quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
    document.addEventListener(&apos;alpine:init&apos;, () =&amp;gt; {

        Alpine.data(&apos;count&apos;, () =&amp;gt; ({
            increment() {
                this.value++;
            },
            value: 0
        }));

    });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we’ve encapsulated the counter logic in &lt;code&gt;increment&lt;/code&gt; and changed the
&lt;code&gt;value&lt;/code&gt; field on each click. There’s no need to do any special syntax to access the
&lt;code&gt;value&lt;/code&gt; field. We can use it as we would a plain-old JavaScript object.&lt;/p&gt;

&lt;p&gt;Now that we understand more about reactivity related to Alpine.js, let’s write a more complex sample that polls our ASP.NET Core application for updated data.&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-and-alpinejs&quot;&gt;ASP.NET Core and Alpine.Js&lt;/h2&gt;

&lt;p&gt;Let’s start by creating an API endpoint that will return weather data. First, let’s look at our data model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Weather
{
    public string Location { get; set; } = &quot;&quot;;
    public string Description { get; set; } = &quot;&quot;;
    public string Temperature { get; set; } = &quot;&quot;;

    public static ReadOnlySpan&amp;lt;string&amp;gt; Descriptions =&amp;gt;
        new([&quot;Sunny&quot;, &quot;Cloudy&quot;, &quot;Rainy&quot;, &quot;Snowy&quot;]);

    public static ReadOnlySpan&amp;lt;string&amp;gt; Locations =&amp;gt;
        new([&quot;Mountain&quot;, &quot;Valley&quot;, &quot;Desert&quot;, &quot;Forest&quot;]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s add a new API endpoint to our application in &lt;code&gt;Program&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MountainWeather.Models;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet(&quot;/weather&quot;, () =&amp;gt;
{
    return Results.Json(
        Enumerable
            .Range(1, 10)
            .Select(i =&amp;gt; new Weather
            {
                Location = $&quot;{Random.Shared.GetItems(Weather.Locations, 1)[0]} #{i}&quot;,
                Description = $&quot;{Random.Shared.GetItems(Weather.Descriptions, 1)[0]}&quot;,
                Temperature = $&quot;{Random.Shared.Next(32, 100)}℉&quot;
            })
            .ToList()
    );
});

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s write our HTML and JavaScript. This is an &lt;code&gt;index.html&lt;/code&gt; file placed in the &lt;code&gt;wwwroot&lt;/code&gt; folder.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;Weather&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://unpkg.com/@picocss/pico@latest/css/pico.min.css&quot;&amp;gt;
    &amp;lt;script src=&quot;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;main class=&quot;container-fluid&quot;&amp;gt;
    &amp;lt;table class=&quot;table table-striped&quot; x-data=&quot;weather&quot;&amp;gt;
        &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;Location&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Temperature&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
        &amp;lt;tr x-show=&quot;locations.length === 0&quot;&amp;gt;
            &amp;lt;td colspan=&quot;3&quot;&amp;gt;
                0 Locations Found.
            &amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;template x-for=&quot;l in locations&quot;&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;td x-text=&quot;l.location&quot;&amp;gt;&amp;lt;/td&amp;gt;
                &amp;lt;td x-text=&quot;l.description&quot;&amp;gt;&amp;lt;/td&amp;gt;
                &amp;lt;td x-text=&quot;l.temperature&quot;&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/template&amp;gt;
        &amp;lt;/tbody&amp;gt;
        &amp;lt;tfoot&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;td colspan=&quot;3&quot; x-text=&quot;updated&quot;&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;/tfoot&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/main&amp;gt;
&amp;lt;script&amp;gt;
    async function getWeather() {
        let result = {};
        const response = await fetch(&apos;/weather&apos;);
        result.locations = await response.json();
        result.updated = new Date();
        return result;
    }

    document.addEventListener(&apos;alpine:init&apos;, () =&amp;gt; {
        Alpine.data(&apos;weather&apos;, () =&amp;gt; ({
            async init() {
                this.timer = setInterval(async () =&amp;gt; {
                    const result = await getWeather();
                    this.locations = result.locations;
                    this.updated = result.updated;
                }, 3000);

                const result = await getWeather();
                this.locations = result.locations;
                this.updated = result.updated;
            },
            destroy: () =&amp;gt; {
                clearInterval(this.timer);
            },
            locations: [],
            updated: &quot;n/a&quot;,
            timer: null
        }));
    });
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let me explain what’s happening in this HTML, starting with our &lt;code&gt;weather&lt;/code&gt; data model. We use the
&lt;code&gt;Alpine.data&lt;/code&gt; method to create a data context that our HTML can use with the
&lt;code&gt;x-data&lt;/code&gt; attribute. This data model has fields for &lt;code&gt;locations&lt;/code&gt;, &lt;code&gt;updated&lt;/code&gt;, and
&lt;code&gt;timer&lt;/code&gt;. The timer fetches data from our API every three seconds and changes the values. When the values change, the UI changes as well.&lt;/p&gt;

&lt;p&gt;Let’s look at HTML binding because Alpine.js allows developers to employ a neat trick: the
&lt;code&gt;template&lt;/code&gt; HTML tag. By default, the
&lt;code&gt;template&lt;/code&gt; tag takes the user-defined contents and appends the hydrated version into the DOM as the following elements. In this sample, we get rows matching the values from the ASP.NET Core API. Now, running the sample, we get a table that updates its values every three seconds.&lt;/p&gt;

&lt;p&gt;Note that JavaScript developers using intervals should call clearInterval if the DOM element can be removed before the user navigates away from the page. This ensures there will be no memory leaks. You can do this using the
&lt;code&gt;destroy&lt;/code&gt; method in your data definition.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you go—a simple, updating UI with minimal JavaScript and an easy-to-understand and maintainable codebase. I like Alpine.js and what it offers. In most cases, a little bit of a user interface can go a long way. I hope you enjoyed this post, and thank you for reading. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 24 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/alpinejs-polling-aspnet-core-apis-for-updates</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/alpinejs-polling-aspnet-core-apis-for-updates</guid>
        
        <category>aspnetcore</category>
        
        <category>javascript</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Building a Persistent Counter with Alpine.Js</title>
        <description>&lt;p&gt;If you read this blog, you likely know I predominantly work with .NET technologies and use web technologies such as HTML, CSS, and JavaScript. The web is an excellent space for new and exciting ways to solve age-old problems. I recently thought about the Blazor “Counter” example that ships with the Blazor Wasm template and how I’ve solved the same problem using Htmx. The issue with Htmx is that it still requires a backend to manage the state; in the case of a counter, this state is the current count. What if you wanted to build a self-contained client-side experience?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://alpinejs.dev/&quot;&gt;Alpine.js&lt;/a&gt; is a declarative library aimed at helping developers build client-side interactivity using HTML attributes on DOM elements. This post will show you how to create the same Blazor Counter example with very little JavaScript and network payloads.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;installing-alpinejs&quot;&gt;Installing Alpine.js&lt;/h2&gt;

&lt;p&gt;Since Alpine.js is a JavaScript library, you only need to reference the necessary files in your HTML pages. In an ASP.NET Core application, that’s typically in your layout files.&lt;/p&gt;

&lt;p&gt;Add the following &lt;code&gt;script&lt;/code&gt; tag to the &lt;code&gt;head&lt;/code&gt; portion of your page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- Alpine Core --&amp;gt;  
&amp;lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it. You can also use NPM to bundle the dependency into an existing build process, but we’ll leave that out of this post for now.&lt;/p&gt;

&lt;h2 id=&quot;building-an-inline-counter-with-alpine&quot;&gt;Building an inline Counter with Alpine&lt;/h2&gt;

&lt;p&gt;Alpine uses attributes, and one of the most important attributes is the &lt;code&gt;x-data&lt;/code&gt; attribute. The &lt;code&gt;x-data&lt;/code&gt; attribute sets up the context for our current scope. In most cases, that scope is the DOM element you decorate with the attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;main class=&quot;container&quot; x-data=&quot;{ count : 0 }&quot;&amp;gt;
    &amp;lt;article class=&quot;card&quot;&amp;gt;
        &amp;lt;header&amp;gt;
            &amp;lt;h3&amp;gt;Counter Value&amp;lt;/h3&amp;gt;
        &amp;lt;/header&amp;gt;
        &amp;lt;section&amp;gt;
            &amp;lt;p x-text=&quot;count&quot;&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;/section&amp;gt;
    &amp;lt;/article&amp;gt;

    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;count++&quot;&amp;gt;
        Increment
    &amp;lt;/button&amp;gt;
    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;count = 0&quot;&amp;gt;
        Reset
    &amp;lt;/button&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow, that’s easy, right? So, how do we persist this information on reloads? Local storage of course!&lt;/p&gt;

&lt;h2 id=&quot;making-the-inline-counter-persistent&quot;&gt;Making the inline counter persistent&lt;/h2&gt;

&lt;p&gt;Alpine.js has a persistence plugin, which we’ll need to install. While you can write the local storage code, this plugin makes it much nicer to use stored values and update them as users make changes.&lt;/p&gt;

&lt;p&gt;Modify the reference to Alpine.js on the page to include these two &lt;code&gt;script&lt;/code&gt; tags.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- Alpine Plugins --&amp;gt;  
&amp;lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;  
&amp;lt;!-- Alpine Core --&amp;gt;  
&amp;lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool, we’re ready to update the HTML to persist the value across page refreshes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;main class=&quot;container&quot; x-data=&quot;{ count : $persist(0) }&quot;&amp;gt;
    &amp;lt;article class=&quot;card&quot;&amp;gt;
        &amp;lt;header&amp;gt;
            &amp;lt;h3&amp;gt;Counter Value&amp;lt;/h3&amp;gt;
        &amp;lt;/header&amp;gt;
        &amp;lt;section&amp;gt;
            &amp;lt;p x-text=&quot;count&quot;&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;/section&amp;gt;
    &amp;lt;/article&amp;gt;

    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;count++&quot;&amp;gt;
        Increment
    &amp;lt;/button&amp;gt;
    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;count = 0&quot;&amp;gt;
        Reset
    &amp;lt;/button&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Refreshing the page now maintains the previous count. What if we want to use that value in other page parts? In other words, what if we want to keep a globally accessible value? That’s where Alpine.js stores come in.&lt;/p&gt;

&lt;h2 id=&quot;persisting-state-in-an-alpine-store&quot;&gt;Persisting state in an Alpine Store&lt;/h2&gt;

&lt;p&gt;Alpine.js allows you to create a global state using a &lt;strong&gt;store&lt;/strong&gt;. Stores are created when Alpine.js initializes the page, allowing you to write more complex logic using JavaScript. Let’s modify our page to use a &lt;code&gt;counter&lt;/code&gt; store with persistent values and methods.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;body&amp;gt;
    &amp;lt;main class=&quot;container&quot; x-data&amp;gt;
        &amp;lt;article class=&quot;card&quot;&amp;gt;
            &amp;lt;header&amp;gt;
                &amp;lt;h3&amp;gt;Counter Value&amp;lt;/h3&amp;gt;
            &amp;lt;/header&amp;gt;
            &amp;lt;section&amp;gt;
                &amp;lt;p x-text=&quot;$store.counter.value&quot;&amp;gt;&amp;lt;/p&amp;gt;
            &amp;lt;/section&amp;gt;
        &amp;lt;/article&amp;gt;
        
        &amp;lt;button type=&quot;button&quot; x-on:click=&quot;$store.counter.increment()&quot;&amp;gt;
            Increment
        &amp;lt;/button&amp;gt;
        &amp;lt;button type=&quot;button&quot; x-on:click=&quot;$store.counter.reset()&quot;&amp;gt;
            Reset
        &amp;lt;/button&amp;gt;             
    &amp;lt;/main&amp;gt;
    &amp;lt;script&amp;gt;
        document.addEventListener(&apos;alpine:initializing&apos;, () =&amp;gt; {
            Alpine.store(&apos;counter&apos;, {
                value: Alpine.$persist(0),
                increment() {
                    this.value++
                },
                reset() {
                    this.value = 0;
                }
            })
        })
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s a bit more JavaScript code, but now other page elements can access the counter store, and the concepts of &lt;code&gt;increment&lt;/code&gt; and &lt;code&gt;reset&lt;/code&gt; are incapsulated into the store, allowing us to change behavior in a single location. That’s pretty cool!&lt;/p&gt;

&lt;p&gt;Here’s the full HTML file so you can try it out for yourself.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot; xmlns:x-on=&quot;http://www.w3.org/1999/xhtml&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;PicoCSS Boilerplate&amp;lt;/title&amp;gt;
    &amp;lt;link
            rel=&quot;stylesheet&quot;
            href=&quot;https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css&quot;
    /&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/site.css&quot;/&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;
    &amp;lt;meta name=&quot;color-scheme&quot; content=&quot;light dark&quot;/&amp;gt;
    &amp;lt;title&amp;gt;Hello World!&amp;lt;/title&amp;gt;
    &amp;lt;!-- Alpine Plugins --&amp;gt;
    &amp;lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;!-- Alpine Core --&amp;gt;
    &amp;lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;main class=&quot;container&quot; x-data&amp;gt;
    &amp;lt;article class=&quot;card&quot;&amp;gt;
        &amp;lt;header&amp;gt;
            &amp;lt;h3&amp;gt;Counter Value&amp;lt;/h3&amp;gt;
        &amp;lt;/header&amp;gt;
        &amp;lt;section&amp;gt;
            &amp;lt;p x-text=&quot;$store.counter.value&quot;&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;/section&amp;gt;
    &amp;lt;/article&amp;gt;

    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;$store.counter.increment()&quot;&amp;gt;
        Increment
    &amp;lt;/button&amp;gt;
    &amp;lt;button type=&quot;button&quot; x-on:click=&quot;$store.counter.reset()&quot;&amp;gt;
        Reset
    &amp;lt;/button&amp;gt;
&amp;lt;/main&amp;gt;
&amp;lt;script&amp;gt;
    document.addEventListener(&apos;alpine:initializing&apos;, () =&amp;gt; {
        Alpine.store(&apos;counter&apos;, {
            value: Alpine.$persist(0),
            increment() {
                this.value++
            },
            reset() {
                this.value = 0;
            }
        })
    })
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Alpine.js is an excellent library for building client-side experiences, and mixing it with Htmx or plain old JavaScript is a winning combination. I hope you try this and experiment with changing the behavior of &lt;code&gt;increment&lt;/code&gt; and &lt;code&gt;reset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts with others. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 17 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/building-a-persistent-counter-with-alpinejs</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/building-a-persistent-counter-with-alpinejs</guid>
        
        <category>javascript</category>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>Dynamic Htmx Islands with ASP.NET Core</title>
        <description>&lt;p&gt;I’m a big fan of static site renderers, and they are still one of the missing elements that would make ASP.NET Core more compelling for users across the vast ecosystem divide. In the meantime, developers must rely on tools like Astro, Jekyll, and 11ty to build static site experiences. Recently, I read about Astro 5.0 and its &lt;a href=&quot;https://5-0-0-beta.docs.astro.build/en/guides/server-islands/&quot;&gt;server island implementation&lt;/a&gt;. Server islands allow for mostly static pages to carve out portions of the page that will be rendered on-demand by, you guessed it, the server. This allows site authors to deliver fast, statically rendered pages that benefit the user while allowing for dynamic user-specific content.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to implement a similar island approach in ASP.NET Core applications that utilize &lt;strong&gt;response and output caching&lt;/strong&gt; for performance increases while still carving out small page sections for dynamic content. We’ll use Htmx to trigger requests for dynamic content based on three exclusive page events.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-an-island&quot;&gt;What is an Island?&lt;/h2&gt;

&lt;p&gt;As described in the introduction, an island is part of the document object model (DOM) that is loaded after the initial page load. This allows the shared DOM across users to be cached while dynamic content specific to a user session is loaded afterward. While a post-load event is commonly used to retrieve dynamic content, islands can also be lazily loaded and take advantage of the &lt;code&gt;revealed&lt;/code&gt; or &lt;code&gt;intersect&lt;/code&gt; events. These will only trigger requests if the user sees this DOM element on the page. Optimizing pages by selecting island events can reduce unnecessary service processing. In general, islands are a powerful technique when building web applications.&lt;/p&gt;

&lt;p&gt;Examples of islands may include a profile name in a page’s navigation, customized recommendations on a storefront, user-based statistics for a dashboard, and more. These islands typically comprise a small yet critical part of the user experience.&lt;/p&gt;

&lt;p&gt;Now, let’s implement an &lt;code&gt;island&lt;/code&gt; component for ASP.NET Core web applications.&lt;/p&gt;

&lt;h2 id=&quot;the-island-plan&quot;&gt;The Island Plan&lt;/h2&gt;

&lt;p&gt;An island has three parts: the initial content, the triggering event, and the endpoint that returns the dynamic content.&lt;/p&gt;

&lt;p&gt;Let’s start by seeing what our &lt;code&gt;island&lt;/code&gt; implementation will look like on a Razor page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;island url=&quot;/profile/avatar&quot;&amp;gt;
    &amp;lt;div class=&quot;alert alert-info d-flex justify-content-center vertical-align-center&quot;&amp;gt;
        &amp;lt;div class=&quot;spinner-border&quot; role=&quot;status&quot;&amp;gt;
            &amp;lt;span class=&quot;visually-hidden&quot;&amp;gt;Loading...&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/island&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;island&lt;/code&gt; element has a URL attribute and some inner content that will be used as a placeholder while dynamic content is loaded. The handler for our dynamic content is a straightforward endpoint, but it could be any backend you choose. What you don’t see in this initial example is a configurable event. We’ll see that in action later in the post.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/profile/avatar&quot;, () =&amp;gt; Results.Content(
    //lang=html
    $&quot;&quot;&quot;
     &amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
        &amp;lt;p class=&quot;fs-1 fw-bold&quot;&amp;gt;🌴 Welcome to the island Khalid!&amp;lt;/p&amp;gt;
        &amp;lt;p class=&quot;fs-3&quot;&amp;gt;You arrived on ({DateTime.Now.ToLongTimeString()})&amp;lt;/p&amp;gt;
     &amp;lt;/div&amp;gt;
     &quot;&quot;&quot;)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, let’s build it!&lt;/p&gt;
&lt;h2 id=&quot;creating-an-island-taghelper&quot;&gt;Creating an Island TagHelper&lt;/h2&gt;

&lt;p&gt;While I initially attempted to do this with a &lt;code&gt;ViewComponent&lt;/code&gt; I found it needing more in what it could accomplish. Tag Helpers are vastly more powerful and capable in this case.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Razor.TagHelpers;

public enum IslandEvents
{
    Load,
    Revealed,
    Intersect
}

[HtmlTargetElement(&quot;island&quot;)]
public class IslandTagHelper : TagHelper
{
    [HtmlAttributeName(&quot;url&quot;), Required]
    public string? Url { get; set; }

    [HtmlAttributeName(&quot;event&quot;)] 
    public IslandEvents Event { get; set; } = IslandEvents.Load;
    
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        // Changing the tag name to &quot;div&quot;
        output.TagName = &quot;div&quot;;

        var @event = Event switch
        {
            IslandEvents.Load =&amp;gt; &quot;load&quot;,
            IslandEvents.Revealed =&amp;gt; &quot;revealed&quot;,
            IslandEvents.Intersect =&amp;gt; &quot;intersect once&quot;,
            _ =&amp;gt; &quot;load&quot;
        };

        output.Attributes.SetAttribute(&quot;hx-get&quot;, Url);
        output.Attributes.SetAttribute(&quot;hx-trigger&quot;, @event);
        output.Attributes.SetAttribute(&quot;hx-swap&quot;, &quot;outerHTML&quot;);

        // Retrieve the inner content
        var childContent = await output.GetChildContentAsync();
        output.Content.SetHtmlContent(childContent);

        // Ensuring the tag is not self-closing
        output.TagMode = TagMode.StartTagAndEndTag;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remember to register the tag helper in &lt;code&gt;_ViewImports.cshtml&lt;/code&gt;. Since we’re using &lt;a href=&quot;https://htmx.org&quot;&gt;Htmx&lt;/a&gt;, you must add the script reference to your &lt;code&gt;_Layout.cshtml&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;https://unpkg.com/htmx.org@2.0.3&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice we have an &lt;code&gt;enum&lt;/code&gt; of &lt;code&gt;IslandEvents&lt;/code&gt;. Let’s discuss what each person does and how their behavior differs.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Load&lt;/strong&gt;: After the initial page load, the page will retrieve the dynamic content.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Revealed&lt;/strong&gt;: The dynamic content will be retrieved only after the element is visible to the user.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Intersect&lt;/strong&gt;: If the element is in an &lt;code&gt;overflow&lt;/code&gt;, the page will only retrieve the dynamic content after it intersects with the visible part of the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at how to change the default loading behavior.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;div style=&quot;margin-top: 2000px&quot;&amp;gt;
    &amp;lt;island url=&quot;/profile/avatar&quot; event=&quot;Revealed&quot;&amp;gt;
        &amp;lt;div class=&quot;alert alert-info d-flex justify-content-center vertical-align-center&quot;&amp;gt;
            &amp;lt;div class=&quot;spinner-border&quot; role=&quot;status&quot;&amp;gt;
                &amp;lt;span class=&quot;visually-hidden&quot;&amp;gt;Loading...&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/island&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the example, the &lt;code&gt;margin-top&lt;/code&gt; is &lt;code&gt;2000px&lt;/code&gt;. This forces us to scroll down to reveal the element, and only then will we call for dynamic content.&lt;/p&gt;

&lt;h2 id=&quot;response-and-output-caching&quot;&gt;Response and Output Caching&lt;/h2&gt;

&lt;p&gt;While not the main focus of this post, response and output caching will be essential to using islands. As mentioned, you want to share as much as possible across user sessions to reap the benefits of these techniques.&lt;/p&gt;

&lt;p&gt;You must update your &lt;code&gt;Program&lt;/code&gt; file to include the following components to add output and response caching—first, the service registrations.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddOutputCache();
builder.Services.AddResponseCaching();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, as part of your ASP.NET Core pipeline, you’ll need to add the following middleware calls.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.UseResponseCaching();
app.UseOutputCache();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once registered, you can apply output caching to the endpoint, which displays most of the content. Here is an example of its use on a Razor page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.OutputCaching;

[OutputCache(Duration = 100),
 ResponseCache(
     Duration = 100,
     Location = ResponseCacheLocation.Any,
     NoStore = false)]
public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    private readonly ILogger&amp;lt;IndexModel&amp;gt; logger = logger;

    public void OnGet()
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Feel free to apply caching to the dynamic endpoints, being mindful of cache-busting based on a user’s session variables.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/profile/avatar&quot;, () =&amp;gt; Results.Content(
    //lang=html
    $&quot;&quot;&quot;
     &amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
        &amp;lt;p class=&quot;fs-1 fw-bold&quot;&amp;gt;🌴 Welcome to the island Khalid!&amp;lt;/p&amp;gt;
        &amp;lt;p class=&quot;fs-3&quot;&amp;gt;You arrived on ({DateTime.Now.ToLongTimeString()})&amp;lt;/p&amp;gt;
     &amp;lt;/div&amp;gt;
     &quot;&quot;&quot;))
    .CacheOutput(policy =&amp;gt; { /* apply caching policy here */ });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you are unfamiliar with caching in ASP.NET Core, &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/performance/caching/output?view=aspnetcore-8.0&quot;&gt;I recommend that you read the official documentation on the topic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There you have it. ASP.NET Core Islands using Htmx.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Some folks may wonder why they should not just do all the caching and reuse on the server, including techniques like [&lt;em&gt;donut caching&lt;/em&gt; and &lt;em&gt;donut hole caching](https://www.computerworld.com/article/1604649/what-exactly-is-donut-caching.html)&lt;/em&gt;. The advantage of this approach is that dynamic content can come from &lt;strong&gt;anywhere&lt;/strong&gt; and isn’t explicitly tied to your ASP.NET Core server backend. You can deliver dynamic content from CDNs, function as service endpoints, use other static sites, and more. It’s a technique that benefits from ASP.NET Core but isn’t tied to it.&lt;/p&gt;

&lt;p&gt;If I spent more time on this implementation, I’d likely integrate islands more closely to ASP.NET Core’s routing mechanisms, allowing users to specify pages, handlers, MVC actions, and more. That said, a simple &lt;code&gt;url&lt;/code&gt; attribute works just fine.&lt;/p&gt;

&lt;p&gt;Finally, TagHelpers are an underrated feature of the ASP.NET Core stack, and I think people should revisit them.&lt;/p&gt;

&lt;p&gt;If you’d like to see a running sample of this project, visit my &lt;strong&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/aspnetcore-htmx-islands&quot;&gt;GitHub repository and try it out for yourself&lt;/a&gt;&lt;/strong&gt;. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 19 Nov 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dynamic-htmx-islands-with-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dynamic-htmx-islands-with-aspnet-core</guid>
        
        <category>aspnet,</category>
        
        <category>htmx</category>
        
        
      </item>
    
      <item>
        <title>Update HTML Elements with Htmx Triggers and ASP.NET Core</title>
        <description>&lt;p&gt;Let me start by saying that I love the combination of &lt;a href=&quot;https://htmx.org&quot;&gt;Htmx&lt;/a&gt; and ASP.NET Core, and it is a pairing that any .NET developer should consider, whether maintaining an existing application or building a new one. It’s very cool. I was recently talking about revisiting the
&lt;code&gt;hx-trigger&lt;/code&gt; and
&lt;code&gt;HX-Trigger&lt;/code&gt; header technique with ASP.NET Core on Mastodon with &lt;a href=&quot;https://mas.to/@illyabusigin&quot;&gt;Illya Busigin&lt;/a&gt;, and they mentioned they use the same method to update the avatar image when a user updates their profile. So, I thought I’d try and see how to implement it myself.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to use the
&lt;code&gt;HX-Trigger&lt;/code&gt; facility in Htmx to update existing UI elements on a rendered HTML page.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-moving-parts&quot;&gt;The Moving Parts&lt;/h2&gt;

&lt;p&gt;When building any new feature in an application, you need to arrange multiple components to work together. Let’s address all the parts you’ll need to make this experience.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A User Profile store&lt;/li&gt;
  &lt;li&gt;Profile Settings endpoints for display and updating&lt;/li&gt;
  &lt;li&gt;An endpoint to refresh the avatar element on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll be using the capabilities of ASP.NET Core Razor Pages and Razor Views to handle the HTML snippets that Htmx needs for swapping elements. Before we get into HTML and Htmx, let’s deal with our user profile storage service.&lt;/p&gt;

&lt;p&gt;Note that you’ll need the NuGet packages of &lt;strong&gt;Htmx&lt;/strong&gt; and, optionally, &lt;strong&gt;Htmx.TagHelpers&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-user-service&quot;&gt;The User Service&lt;/h2&gt;

&lt;p&gt;I created a straightforward class for the demo that will hold the user name and the avatar URL. In a “real application”, you’d likely store this information in a database or third-party auth service. Let’s see what I wrote.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class UserService
{
    public static readonly string[] AvatarUrls =
    [
        &quot;~/img/avatar_one.png&quot;,
        &quot;~/img/avatar_two.png&quot;,
        &quot;~/img/avatar_three.png&quot;,
    ];
    
    public string Name { get; set; } = &quot;Khalid Abuhakmeh&quot;;
    public string AvatarUrl { get; set; } = AvatarUrls[0];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The user can choose from three existing avatars, which are stored in the
&lt;code&gt;wwwroot/img&lt;/code&gt; folder. Fewer options mean less code for the demo and more focus on the Htmx bits that come later.&lt;/p&gt;

&lt;p&gt;Next, we’ll register the &lt;code&gt;UserService&lt;/code&gt; as a
&lt;code&gt;Singleton&lt;/code&gt; in our ASP.NET Core setup class to maintain the state between requests. &lt;strong&gt;Note: This is only for the demo
and is not recommended in any other scenario.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSingleton&amp;lt;UserService&amp;gt;();

var app = builder.Build();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! Now, we can inject this service where we need it to grab the current state of the user profile, which includes the name and avatar URL.&lt;/p&gt;

&lt;p&gt;I inject this service into my &lt;code&gt;Layout.cshtml&lt;/code&gt; and then render the avatar partial.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@inject UserService UserService
&amp;lt;!-- some HTML --&amp;gt;
@await Html.PartialAsync(&quot;_Avatar&quot;, UserService)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll examine the partial later in the article, but first, let’s discuss our account endpoints.&lt;/p&gt;

&lt;h2 id=&quot;profile-endpoints&quot;&gt;Profile Endpoints&lt;/h2&gt;

&lt;p&gt;In a new Razor page titled &lt;code&gt;Index&lt;/code&gt;, we’ll have three endpoints:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Show the profile settings form.&lt;/li&gt;
  &lt;li&gt;Accept user updates&lt;/li&gt;
  &lt;li&gt;Render the &lt;code&gt;_Avatar&lt;/code&gt; profile image as partial content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll paste the full class here, and we’ll break it down into one endpoint at a time.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Diagnostics.CodeAnalysis;
using Htmx;
using HtmxAvatarChange.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace HtmxAvatarChange.Pages;

public class IndexModel(UserService userService, ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    [BindProperty] public string? Name { get; set; }

    [BindProperty] public string? AvatarUrl { get; set; }

    [TempData] public string? Message { get; set; }
    [TempData] public string? MessageCssClass { get; set; }

    [MemberNotNullWhen(true, nameof(Message))]
    public bool HasMessage =&amp;gt; Message != null;

    public List&amp;lt;SelectListItem&amp;gt; Avatars =&amp;gt; UserService
        .AvatarUrls
        .Select((x, i) =&amp;gt; new SelectListItem($&quot;avatar-{i:00}&quot;, x))
        .ToList();

    public void OnGet()
    {
        Name = userService.Name;
        AvatarUrl = userService.AvatarUrl;
    }

    public IActionResult OnPost()
    {
        if (ModelState.IsValid)
        {
            Message = &quot;Successfully saved account settings&quot;;
            MessageCssClass = &quot;alert-success&quot;;

            // change values
            userService.Name = Name!;
            userService.AvatarUrl = AvatarUrl!;
            
            Response.Htmx(h =&amp;gt;
                h.WithTrigger(&quot;avatar&quot;));
        }
        else
        {
            Message = &quot;Failed to save account settings&quot;;
            MessageCssClass = &quot;alert-danger&quot;;
        }

        if (Request.IsHtmx())
        {
            return Partial(&quot;_Form&quot;, this);
        }

        return RedirectToPage(&quot;Index&quot;);
    }

    public IActionResult OnGetAvatar()
    {
        return Partial(&quot;_Avatar&quot;, userService);
    }

    public string? IsCurrentAvatar(string avatarValue)
    {
        return avatarValue == AvatarUrl ? &quot;checked&quot; : null;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first method we’ll look at is &lt;code&gt;OnGet&lt;/code&gt;. This method takes the information from the
&lt;code&gt;UserService&lt;/code&gt; and hydrates our property. These properties will be used to bind information to our form.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public void OnGet()
{
	Name = userService.Name;
	AvatarUrl = userService.AvatarUrl;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, closer to the bottom of the class, let’s look at a similar method, &lt;code&gt;OnGetAvatar&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public IActionResult OnGetAvatar()
{
	return Partial(&quot;_Avatar&quot;, userService);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This method returns the partial view of &lt;code&gt;_Avatar&lt;/code&gt;, simply displaying our user information. Now, let’s look at the
&lt;code&gt;OnPost&lt;/code&gt; method, which is the juiciest of the implementations.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public IActionResult OnPost()
{
	if (ModelState.IsValid)
	{
		Message = &quot;Successfully saved account settings&quot;;
		MessageCssClass = &quot;alert-success&quot;;

		// change values
		userService.Name = Name!;
		userService.AvatarUrl = AvatarUrl!;
		
		Response.Htmx(h =&amp;gt;
			h.WithTrigger(&quot;avatar&quot;));
	}
	else
	{
		Message = &quot;Failed to save account settings&quot;;
		MessageCssClass = &quot;alert-danger&quot;;
	}

	if (Request.IsHtmx())
	{
		return Partial(&quot;_Form&quot;, this);
	}

	return RedirectToPage(&quot;Index&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we determine if the user input is valid and then update the page. The two most important lines include the
&lt;code&gt;Htmx&lt;/code&gt; references.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Response.Htmx(h =&amp;gt;
	h.WithTrigger(&quot;avatar&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the incoming request was initiated with Htmx, we add a response header to tell Htmx to fire a client-side event of
&lt;code&gt;avatar&lt;/code&gt;. Any element subscribing to this event will then trigger another request. In our case, we’ll be calling the
&lt;code&gt;OnGetAvatar&lt;/code&gt; endpoint. You can add as many events as you need here, but we only want one in our case.&lt;/p&gt;

&lt;p&gt;The following reference to Htmx checks if Htmx initiated the request. If it was, we need to send back a partial Html snippet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;if (Request.IsHtmx())
{
	return Partial(&quot;_Form&quot;, this);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it! But what do the Razor views look like?&lt;/p&gt;

&lt;h2 id=&quot;htmx-and-partial-views&quot;&gt;Htmx and Partial Views&lt;/h2&gt;

&lt;p&gt;Let’s start with the form since it is the focal point of our user experience. It’s straightforward Razor code with one exception: the Htmx attributes on the
&lt;code&gt;form&lt;/code&gt; tag.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@model IndexModel

&amp;lt;fieldset id=&quot;account-settings&quot;&amp;gt;
    &amp;lt;legend&amp;gt;Account Settings&amp;lt;/legend&amp;gt;

    @if (Model.HasMessage)
    {
        &amp;lt;div class=&quot;alert @(Model.MessageCssClass ?? &quot;alert-info&quot;)&quot; role=&quot;alert&quot;&amp;gt;
            @Model.Message
        &amp;lt;/div&amp;gt;
    }

    &amp;lt;form method=&quot;post&quot; hx-post hx-target=&quot;#account-settings&quot; hx-swap=&quot;outerHTML&quot;&amp;gt;
        &amp;lt;div class=&quot;form-group row&quot;&amp;gt;
            &amp;lt;label asp-for=&quot;Name&quot; class=&quot;col-sm-2 col-form-label&quot;&amp;gt;Name&amp;lt;/label&amp;gt;
            &amp;lt;div class=&quot;col-sm-10&quot;&amp;gt;
                &amp;lt;input class=&quot;form-control&quot; asp-for=&quot;Name&quot;&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;fieldset class=&quot;form-group mt-3&quot;&amp;gt;
            &amp;lt;div class=&quot;row&quot;&amp;gt;
                &amp;lt;legend class=&quot;col-form-label col-sm-2 pt-0&quot;&amp;gt;Avatar&amp;lt;/legend&amp;gt;
                &amp;lt;div class=&quot;col-sm-10&quot;&amp;gt;
                    @foreach (var avatar in Model.Avatars)
                    {
                        &amp;lt;div class=&quot;form-check&quot;&amp;gt;
                            &amp;lt;input
                                id=&quot;@avatar.Text&quot;
                                asp-for=&quot;AvatarUrl&quot;
                                class=&quot;form-check-inline&quot; type=&quot;radio&quot;
                                value=&quot;@avatar.Value&quot;
                                checked=&quot;@Model.IsCurrentAvatar(avatar.Value)&quot;&amp;gt;
                            &amp;lt;label class=&quot;form-check-label&quot; for=&quot;@avatar.Text&quot;&amp;gt;
                                &amp;lt;img src=&quot;@Url.Content(avatar.Value)&quot; class=&quot;profile-pic&quot; alt=&quot;@avatar.Text&quot;/&amp;gt;
                            &amp;lt;/label&amp;gt;
                        &amp;lt;/div&amp;gt;
                    }
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/fieldset&amp;gt;
        &amp;lt;div class=&quot;form-group row mt-3&quot;&amp;gt;
            &amp;lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&amp;gt;Save Profile&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/fieldset&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These Htmx attributes allow us to hijack the form submission and route it through an Htmx request, allowing the library to process the header request. Once processed, it fires the event on the
&lt;code&gt;_Avatar&lt;/code&gt; partial. Let’s take a look at that view now.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@model HtmxAvatarChange.Models.UserService

&amp;lt;div id=&quot;profile-avatar&quot;
     class=&quot;mx-2 smooth&quot;
     hx-get=&quot;@Url.Page(&quot;Index&quot;, &quot;Avatar&quot;)&quot;
     hx-trigger=&quot;avatar from:body&quot;&amp;gt;
    &amp;lt;div class=&quot;profile-pic&quot;&amp;gt;
        &amp;lt;img src=&quot;@Url.Content(Model.AvatarUrl)&quot; alt=&quot;Profile Picture&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;span class=&quot;navbar-text&quot;&amp;gt; @Model.Name&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The essential attribute on this view is the &lt;code&gt;hx-trigger&lt;/code&gt; attribute. Note the exact value.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;hx-trigger=&quot;avatar from:body&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;from:body&lt;/code&gt; is essential, as the
&lt;code&gt;body&lt;/code&gt; element is what Htmx uses to broadcast the event. That’s it. Let’s see it in action!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/khalidabuhakmeh/HtmxAvatarChange/raw/main/misc/htmx-hx-trigger-sample.gif&quot; alt=&quot;Sample Running&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wow! That’s cool!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;HX-Trigger&lt;/code&gt; headers can help you decouple UI elements from each other and create a system of elements that can act independently. This can be very powerful, but it should be used in moderation, like all things. Remember, each triggered event results in a request back to the server, which could come at a cost. That said, many existing SPA UI approaches already make expensive calls to the server, so this might not be any worse than a GraphQL call or JSON over an HTTP request.&lt;/p&gt;

&lt;p&gt;I’ve uploaded the code for this sample to my &lt;a href=&quot;https://github.com/khalidabuhakmeh/HtmxAvatarChange&quot;&gt;GitHub repository&lt;/a&gt; so you can try it out.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and hope you give this one a try.&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/update-html-elements-with-htmx-triggers-and-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/update-html-elements-with-htmx-triggers-and-aspnet-core</guid>
        
        <category>htmx,</category>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Add EF Core Migrations to .NET Aspire Solutions</title>
        <description>&lt;p&gt;Folks working with EF Core are likely very fond of the library’s migration features, one of the most vital selling points for adopting an ORM. If you’re building a .NET solution, your database schema will evolve, and adding, removing, and updating are everyday actions you must perform.&lt;/p&gt;

&lt;p&gt;.NET Aspire can ease the development of distributed solutions, but you still need to bridge the gap between development time actions and runtime execution. With EF Core, a development time action is managing migrations, while at runtime, you’ll need to execute those migrations against a database. The &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/aspire/database/ef-core-migrations&quot;&gt;original tutorial by the Microsoft documentation&lt;/a&gt; explains how to run a .NET Aspire application with migrations but leaves out how to do development time tasks.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to manage migrations during the development process so you can get the most out of your .NET Aspire and Entity Framework Core adoption.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-solution-structure&quot;&gt;The Solution Structure&lt;/h2&gt;

&lt;p&gt;We’ll first need to understand the solution structure of our Aspire distributed application. This is what my solution looks like, but you can change the approach depending on your preferences.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;AspireSandbox
|- AspireSandbox.AppHost
|- AspireSandbox.Data
|- AspireSandbox.ServiceDefaults
|- AspireSandbox.Web
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;AspireSanbox.Data&lt;/code&gt; project contains my &lt;code&gt;DbContext&lt;/code&gt; implementation, which is nothing remarkable.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;

namespace AspireSandbox.Data;

public class Database(DbContextOptions&amp;lt;Database&amp;gt; options) 
    : DbContext(options)
{
    public DbSet&amp;lt;Count&amp;gt; Counts =&amp;gt; Set&amp;lt;Count&amp;gt;();
}

public class Count
{
    public int Id { get; set; }
    public DateTimeOffset CountedAt { get; set; } = DateTimeOffset.UtcNow;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The dependencies for this project include the following Entity Framework Core packages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&amp;gt;

    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;
        &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
        &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

    &amp;lt;ItemGroup&amp;gt;
      &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore&quot; Version=&quot;8.0.8&quot; /&amp;gt;
      &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore.Design&quot; Version=&quot;8.0.8&quot;&amp;gt;
        &amp;lt;PrivateAssets&amp;gt;all&amp;lt;/PrivateAssets&amp;gt;
        &amp;lt;IncludeAssets&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/IncludeAssets&amp;gt;
      &amp;lt;/PackageReference&amp;gt;
      &amp;lt;PackageReference Include=&quot;Npgsql.EntityFrameworkCore.PostgreSQL&quot; Version=&quot;8.0.8&quot; /&amp;gt;
    &amp;lt;/ItemGroup&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we must add this project as a reference to our
&lt;code&gt;AspireSandbox.AppHost&lt;/code&gt; project, paying attention to adding the attribute of
&lt;code&gt;IsAspireProjectResource&lt;/code&gt; and setting its value to &lt;code&gt;false&lt;/code&gt;. This opts this project out of the Aspire source generators.&lt;/p&gt;

&lt;p&gt;I have a few other package references, but pay attention to the Entity Framework Core dependencies.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&amp;gt;

    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;OutputType&amp;gt;Exe&amp;lt;/OutputType&amp;gt;
        &amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;
        &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
        &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
        &amp;lt;IsAspireHost&amp;gt;true&amp;lt;/IsAspireHost&amp;gt;
        &amp;lt;UserSecretsId&amp;gt;ba2648f9-6953-4e8b-9918-c241b1d99b09&amp;lt;/UserSecretsId&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

    &amp;lt;ItemGroup&amp;gt;
        &amp;lt;PackageReference Include=&quot;Aspire.Hosting.AppHost&quot; Version=&quot;8.2.1&quot;/&amp;gt;
        &amp;lt;PackageReference Include=&quot;Aspire.Hosting.PostgreSQL&quot; Version=&quot;8.2.1&quot; /&amp;gt;
        &amp;lt;PackageReference Include=&quot;Aspire.Hosting.Redis&quot; Version=&quot;8.2.1&quot; /&amp;gt;
        &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore&quot; Version=&quot;8.0.8&quot; /&amp;gt;
        &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore.Design&quot; Version=&quot;8.0.8&quot;&amp;gt;
          &amp;lt;PrivateAssets&amp;gt;all&amp;lt;/PrivateAssets&amp;gt;
          &amp;lt;IncludeAssets&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/IncludeAssets&amp;gt;
        &amp;lt;/PackageReference&amp;gt;
    &amp;lt;/ItemGroup&amp;gt;

    &amp;lt;ItemGroup&amp;gt;
      &amp;lt;ProjectReference Include=&quot;..\AspireSandbox.Data\AspireSandbox.Data.csproj&quot; 
                        IsAspireProjectResource=&quot;false&quot; /&amp;gt;
      &amp;lt;ProjectReference Include=&quot;..\AspireSandbox.Web\AspireSandbox.Web.csproj&quot; /&amp;gt;
    &amp;lt;/ItemGroup&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, we’re ready to write some code.&lt;/p&gt;

&lt;h2 id=&quot;entity-framework-core-design-time-factory&quot;&gt;Entity Framework Core Design Time Factory&lt;/h2&gt;

&lt;p&gt;Entity Framework Core provides a mechanism for the tooling to connect and work with a database. Since our database is in the scope of our distributed application, we need to run our tooling when Aspire has built our dependency. Don’t worry; it will make sense in a second.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;AspireSandbox.AppHost&lt;/code&gt;, create a new &lt;code&gt;DataContextDesignTimeFactory&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace AspireSandbox.AppHost;

public sealed class DataContextDesignTimeFactory :
	IDesignTimeDbContextFactory&amp;lt;Data.Database&amp;gt;
{
    public Data.Database CreateDbContext(string[] args)
    {
        var builder = DistributedApplication.CreateBuilder(args);
    
        var postgres = builder
            .AddPostgres(&quot;postgres&quot;)
            .AddDatabase(&quot;migrations&quot;, databaseName: &quot;migrations&quot;);

        var optionsBuilder = new DbContextOptionsBuilder&amp;lt;Data.Database&amp;gt;();
        optionsBuilder.UseNpgsql(&quot;migrations&quot;);
        return new Data.Database(optionsBuilder.Options);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This implementation will spin up our database dependency and allow us to create an instance of our
&lt;code&gt;DbContext&lt;/code&gt; implementation. At least long enough to create and add our migrations to our project. Remember that EF Core creates a model snapshot as a C# file, so there is no need to persist the database across migration runs.&lt;/p&gt;

&lt;h2 id=&quot;ef-core-cli-command&quot;&gt;EF Core CLI Command&lt;/h2&gt;

&lt;p&gt;Now, we can run the following command to spin up Aspire long enough to create a migration.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet ef migrations --project ./AspireSandbox.Data --startup-project ./AspireSandbox.AppHost add Initial
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Change the &lt;code&gt;--project&lt;/code&gt; and &lt;code&gt;--startup-project&lt;/code&gt; to match your solution structure.&lt;/p&gt;

&lt;p&gt;If all goes well, you should now have a new database migration.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you have it; you can now work seamlessly between your development environment and Aspire solution with just a new
&lt;code&gt;IDesignTimeDbContextFactory&lt;/code&gt; implementation and tweaking your CLI command.&lt;/p&gt;

&lt;p&gt;Thanks to James Hancock for leaving this comment on the Aspire GitHub issues and inspiring this blog post. His solution is pretty
&lt;strong&gt;+$%!&lt;/strong&gt; good.&lt;/p&gt;
</description>
        <pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/add-ef-core-migrations-to-dotnet-aspire-solutions</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/add-ef-core-migrations-to-dotnet-aspire-solutions</guid>
        
        <category>aspire,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Htmx and Playwright Tests in C#</title>
        <description>&lt;p&gt;Community member Jonathan Channon recently approached me about an appropriate way to test your Htmx-powered applications using the Playwright testing framework. It can be annoying to get the timing right between sending an HTMX request, processing it on the server, and applying it to the page.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see a surefire way to wait for Htmx to finish before testing the state of your pages, thus leading to more reliable tests and faster test execution. Let’s go.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-htmx-counter-application&quot;&gt;The Htmx Counter Application&lt;/h2&gt;

&lt;p&gt;Let’s first see what application we’ll be testing. It’s a simple **Counter
** component that increases in value when the user presses a button.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@model HtmxPlaywrightIntegration.ViewModels.CounterViewModel

&amp;lt;div id=&quot;counter&quot; class=&quot;card&quot;&amp;gt;
    &amp;lt;div id=&quot;value&quot; class=&quot;card-body&quot;&amp;gt;
        @Model.Count
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;card-footer&quot;&amp;gt;
        &amp;lt;form asp-page=&quot;Index&quot; method=&quot;post&quot; 
              hx-post 
              hx-target=&quot;#counter&quot;
              hx-swap=&quot;outerHTML&quot;&amp;gt;
            &amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The ASP.NET Core endpoint is straightforward.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using HtmxPlaywrightIntegration.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace HtmxPlaywrightIntegration.Pages;

public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    public static CounterViewModel Value { get; set; }
        = new();

    public void OnGet()
    {
    }

    public IActionResult OnPost()
    {
        Value.Count += 1;
        return Partial(&quot;_Counter&quot;, Value);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Clicking the button will make a request to the server, increment the value, and return the HTML snippet to be processed into the page.&lt;/p&gt;

&lt;p&gt;Now, let’s move on to the next part of the process, the Htmx lifecycle.&lt;/p&gt;

&lt;h2 id=&quot;htmx-request-lifecycle-events&quot;&gt;Htmx Request Lifecycle Events&lt;/h2&gt;

&lt;p&gt;Htmx contains multiple lifecycle events that we can utilize during a request. These events allow us to modify outgoing requests and understand what stages Htmx is at during the processing phase.&lt;/p&gt;

&lt;p&gt;The lifecycle event we are most interested in is
&lt;code&gt;htmx:afterSettle&lt;/code&gt;. Settling is the process after all DOM changes have been applied and the page is now stable. Let’s hook into this page event and write a console message. I’ve added this to the typical
&lt;code&gt;site.js&lt;/code&gt; file, but it can go anywhere within your application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;document.body.addEventListener(&apos;htmx:afterSettle&apos;, function(evt) {
    console.log(&apos;playwright:continue&apos;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, whenever we settle the page, a console message will be written with the value of
&lt;code&gt;playwright:continue&lt;/code&gt;. We’ll see how to register this script into our page in the next section using the Playwright APIs.&lt;/p&gt;

&lt;h2 id=&quot;playwright-and-htmx-extensions&quot;&gt;Playwright and Htmx Extensions&lt;/h2&gt;

&lt;p&gt;Now, let’s look at our test.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace HtmxPlaywrightIntegration.Tests;

[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class Tests : PageTest
{
    [Test]
    public async Task CanIncrementCountUsingHtmx()
    {
        await Page.GotoAsync(&quot;http://localhost:5170&quot;);

        await Page.RegisterHtmxLifecycleListener();

        var button = Page.Locator(&quot;text=Increment&quot;);
        var body = Page.Locator(&quot;#value&quot;);

        var currentCount = int.Parse(await body.TextContentAsync() ?? &quot;-1&quot;);

        await button.ClickAsync();
        await Page.WaitForHtmx();
        
        await Expect(body).ToHaveTextAsync($&quot;{currentCount+1}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We first call the &lt;code&gt;RegisterHtmxLifecycleListener&lt;/code&gt; script. This is the same JavaScript seen above. Then, we call
&lt;code&gt;WaitForHtmx&lt;/code&gt;, which will wait for the console message in our page’s output. Let’s see how these extension methods work.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Playwright;

namespace HtmxPlaywrightIntegration.Tests;

public static class HtmxExtensions
{
    private const string Continue = &quot;playwright:continue&quot;;
    
    public static Task WaitForHtmx(this IPage page)
    {
        return page.WaitForConsoleMessageAsync(new() {
            Predicate = message =&amp;gt; message.Text == Continue
        });
    }

    public static Task RegisterHtmxLifecycleListener(this IPage page)
    {
        return page.AddScriptTagAsync(new()
        {
            // language=javascript
            Content = $$&quot;&quot;&quot;
                      document.body.addEventListener(&apos;htmx:afterSettle&apos;, function(evt) {
                          console.log(&apos;{{Continue}}&apos;);
                      });
                      &quot;&quot;&quot;
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s that easy. Now, your Playwright tests can wait for messages generated by the Htmx lifecycle, so you don’t have to worry about changes to your implementation on the front or back end changing how your tests execute. Additionally, you won’t have to waste time waiting for random delays to progress through your tests.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful. Have fun building Htmx apps tested by Playwright. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/htmx-and-playwright-tests-in-csharp</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/htmx-and-playwright-tests-in-csharp</guid>
        
        <category>htmx,</category>
        
        <category>playwright</category>
        
        
      </item>
    
      <item>
        <title>Intersperse Values for Enumerable Collections</title>
        <description>&lt;p&gt;JavaScript, for better or worse, has a much smaller standard library than what .NET developers are used to with the base class library (BCL). The JavaScript community has made many attempts to build &lt;a href=&quot;https://www.npmjs.com/search?q=standard%20library&quot;&gt;a standard library&lt;/a&gt;, and I’m sure some of them are great. As I was scanning the options, I came across a fascinating method named &lt;a href=&quot;https://js-std.pages.dev/Array/intersperse&quot;&gt;
&lt;code&gt;intersperse&lt;/code&gt;&lt;/a&gt;, which “inserts a separator between the elements of its list argument”.&lt;/p&gt;

&lt;p&gt;In this post, I’ll implement the same method in C# as an extension method on the &lt;code&gt;IEnumerable&lt;/code&gt; interface.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;intersperse-implementation-in-c&quot;&gt;Intersperse implementation in C#&lt;/h2&gt;

&lt;p&gt;Let’s first look at a few examples and the expected output before we look at the implementation of the method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var hello = new string(&quot;Hello&quot;.Intersperse(&apos;-&apos;).ToArray());
var one = new string(&quot;1&quot;.Intersperse(&apos;x&apos;).ToArray());
var @null = ((IEnumerable&amp;lt;object&amp;gt;)null!).Intersperse(&apos;,&apos;).ToArray();
var array = new[] { 1, 2, 3 }.Intersperse(42).ToArray();
var menu = new [] {&quot;Home&quot;, &quot;About&quot;, &quot;Privacy&quot; }
    .Intersperse(&quot; &amp;gt; &quot;)
    .Aggregate((a, b) =&amp;gt; $&quot;{a}{b}&quot;);

Console.WriteLine($&quot;&apos;{hello}&apos; interspersed with &apos;-&apos; is {hello}&quot;);
Console.WriteLine($&quot;1 interspersed is {one}&quot;);
Console.WriteLine($&quot;null interspersed is {@null}&quot;);
Console.WriteLine($&quot;array interspersed is {string.Join(&quot;, &quot;, array)}&quot;);
Console.WriteLine($&quot;The menu is {menu}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running this application, we will see the following output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;&apos;H-e-l-l-o&apos; interspersed with &apos;-&apos; is H-e-l-l-o
1 interspersed is 1
null interspersed is System.Object[]
array interspersed is 1, 42, 2, 42, 3
The menu is Home &amp;gt; About &amp;gt; Privacy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s get to the implementation!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class EnumerableExtensions
{
    public static IEnumerable&amp;lt;T&amp;gt; Intersperse&amp;lt;T&amp;gt;(
        this IEnumerable&amp;lt;T&amp;gt;? source,
        T delimiter)
    {
        if (source is null) yield break;

        using var enumerator = source.GetEnumerator();
        var hasFirstElement = enumerator.MoveNext();
        
        if (hasFirstElement == false) yield break;
        
        yield return enumerator.Current;

        while (enumerator.MoveNext())
        {
            yield return delimiter;
            yield return enumerator.Current;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I used
&lt;code&gt;yield&lt;/code&gt; to reduce the number of iterations on the collection being passed, as it would add unnecessary overhead. Additionally, I could have used a method like
&lt;code&gt;Zip&lt;/code&gt;, but that would have required more gymnastics than the current implementation.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this quick blog post, and as always, thanks for reading. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 10 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/intersperse-values-for-enumerable-collections</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/intersperse-values-for-enumerable-collections</guid>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Checked and Unchecked Arithmetic Operations in .NET</title>
        <description>&lt;p&gt;The other day, I played around with the Fibonacci sequence and overflowed my
&lt;code&gt;int&lt;/code&gt; variables in surprisingly low iterations. Did you know you’ll overflow an integer in **48
** iterations? Don’t believe me? Let’s take a look at the result of the code you’ll see later in this post.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Enter an integer: 48
Fibonacci sequence for 48:
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,
317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580
141,267914296,433494437,701408733,1134903170,1836311903,-1323752223
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice that the last value has looped back to a negative value. Oh no! This is a tell-tale sign that an overflow has occurred.&lt;/p&gt;

&lt;p&gt;This post will explore how to keep your applications safe from these overflow issues.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-code-causing-the-overflow&quot;&gt;The code causing the overflow&lt;/h2&gt;

&lt;p&gt;First, let’s look at my implementation of the Fibonacci sequence generator. I’m using
&lt;code&gt;Spectre.Console&lt;/code&gt; to make the output more appealing, but it’s optional. I’m also using the
&lt;code&gt;System.Numerics&lt;/code&gt; namespace, which will allow you to experiment with different number types in .NET.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Numerics;
using Spectre.Console;

while (true)
{
    try
    {
        var integer = AnsiConsole.Ask&amp;lt;int&amp;gt;(&quot;Enter an integer: &quot;);

        if (integer &amp;lt;= -1)
        {
            AnsiConsole.MarkupLine(&quot;Goodbye!&quot;);
            break;
        }

        var numbers = GenerateFibonacci&amp;lt;int&amp;gt;((uint)integer);
        AnsiConsole.MarkupLine($&quot;[bold green]Fibonacci sequence for {integer}:[/]&quot;);
        AnsiConsole.MarkupLine($&quot;[bold yellow]{string.Join(&quot;,&quot;, numbers)}[/]&quot;);
        AnsiConsole.MarkupLine(&quot;&quot;);
    }
    catch (ArgumentOutOfRangeException)
    {
        AnsiConsole.MarkupLine(&quot;[red]Error: pick a value greater than 2[/]&quot;);
    }
}

static T[] GenerateFibonacci&amp;lt;T&amp;gt;(uint iterations)
    where T : INumber&amp;lt;T&amp;gt;
{
    ArgumentOutOfRangeException
        .ThrowIfLessThan&amp;lt;uint&amp;gt;(iterations, 2, &quot;iterations must be greater than or equal to 2&quot;);

    T[] fib = new T[iterations];
    fib[0] = T.Zero;
    fib[1] = T.One;
    for (int i = 2; i &amp;lt; iterations; i++)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat! Now, why does the issue occur in the first place?&lt;/p&gt;

&lt;h2 id=&quot;unchecked-arithmetic&quot;&gt;Unchecked Arithmetic&lt;/h2&gt;

&lt;p&gt;By default, .NET performs
&lt;code&gt;unchecked&lt;/code&gt; arithmetic operations. That means the runtime assumes you know what you’re doing when adding one variable to another. This is true in most day-to-day cases, as the scale of numbers most developers deal with is on the lower side of the maximum
&lt;code&gt;int&lt;/code&gt; and &lt;code&gt;long&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;For integers, the max value is &lt;code&gt;2147483647&lt;/code&gt;, and it is doubled to &lt;code&gt;4294967295&lt;/code&gt; if you drop the sign
&lt;code&gt;—/+&lt;/code&gt; from the value. For a long, the max value is
&lt;code&gt;9223372036854775807&lt;/code&gt;, which is quite a lot bigger but not infinite. If your application increments values indefinitely, you will run into overflow issues, and no known type will save you. It’s just math!&lt;/p&gt;

&lt;p&gt;As you’ve seen previously, the issue is that the numbers will loop around from positive to negative values and back. Your application will continue to “work” but likely will be nonsensical and wrong.&lt;/p&gt;

&lt;p&gt;How do we fix this issue? Well, there are two ways.&lt;/p&gt;

&lt;h2 id=&quot;the-checked-keyword&quot;&gt;The &lt;code&gt;checked&lt;/code&gt; keyword&lt;/h2&gt;

&lt;p&gt;The first and most precise way to fix this issue is to use the
&lt;code&gt;checked&lt;/code&gt; keyword. Using this keyword creates a scope where arithmetic overflows will trigger an &lt;code&gt;OverflowException&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;static T[] GenerateFibonacci&amp;lt;T&amp;gt;(uint iterations)
    where T : INumber&amp;lt;T&amp;gt;
{
    ArgumentOutOfRangeException
        .ThrowIfLessThan&amp;lt;uint&amp;gt;(iterations, 2, &quot;iterations must be greater than or equal to 2&quot;);

    T[] fib = new T[iterations];
    fib[0] = T.Zero;
    fib[1] = T.One;
    for (int i = 2; i &amp;lt; iterations; i++)
    {
        checked
        {
            fib[i] = fib[i - 1] + fib[i - 2];
        }
    }

    return fib;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rerunning the same code results in the following exception.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Enter an integer: 49
Unhandled exception. System.OverflowException: Arithmetic operation resulted in an overflow.
   at System.Int32.System.Numerics.IAdditionOperators&amp;lt;System.Int32,System.Int32,System.Int32&amp;gt;.op_CheckedAddition(Int32 left, Int32 right)
   at Program.&amp;lt;&amp;lt;Main&amp;gt;$&amp;gt;g__GenerateFibonacci|0_0[T](UInt32 iterations) in /Users/khalidabuhakmeh/RiderProjects/zed-sample/Program.cs:line 40
   at Program.&amp;lt;Main&amp;gt;$(String[] args) in /Users/khalidabuhakmeh/RiderProjects/zed-sample/Program.cs:line 16
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice. This technique is very selective and changes the intermediate language to call the
&lt;code&gt;op_CheckedAddition&lt;/code&gt; method instead.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;      // [40 13 - 40 46]
      IL_003f: ldloc.0      // fib
      IL_0040: ldloc.1      // i
      IL_0041: ldloc.0      // fib
      IL_0042: ldloc.1      // i
      IL_0043: ldc.i4.1
      IL_0044: sub.ovf
      IL_0045: ldelem       !!0/*T*/
      IL_004a: ldloc.0      // fib
      IL_004b: ldloc.1      // i
      IL_004c: ldc.i4.2
      IL_004d: sub.ovf
      IL_004e: ldelem       !!0/*T*/
      IL_0053: constrained. !!0/*T*/
      IL_0059: call         !2/*T*/ class [System.Runtime]System.Numerics.IAdditionOperators`3&amp;lt;!!0/*T*/, !!0/*T*/, !!0/*T*/&amp;gt;::op_CheckedAddition(!0/*T*/, !1/*T*/)
      IL_005e: stelem       !!0/*T*/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! Problem solved, but what if we want all our arithmetic checked?&lt;/p&gt;

&lt;h2 id=&quot;project-setting-for-checked-arithmetic&quot;&gt;Project Setting for Checked Arithmetic&lt;/h2&gt;

&lt;p&gt;You can add the
&lt;code&gt;CheckForOverflowUnderflow&lt;/code&gt; property in your project settings, and it will change all supported arithmetic operations to use checked operations.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&amp;gt;

  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;OutputType&amp;gt;Exe&amp;lt;/OutputType&amp;gt;
    &amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;
    &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
    &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
    &amp;lt;CheckForOverflowUnderflow&amp;gt;true&amp;lt;/CheckForOverflowUnderflow&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;

  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;PackageReference Include=&quot;Spectre.Console&quot; Version=&quot;0.49.1&quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Easy peasy. Running the original code results in the same &lt;code&gt;System.OverflowException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To opt out of checking, you can use the converse &lt;code&gt;unchecked&lt;/code&gt; keyword.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;static T[] GenerateFibonacci&amp;lt;T&amp;gt;(uint iterations)
    where T : INumber&amp;lt;T&amp;gt;
{
    ArgumentOutOfRangeException
        .ThrowIfLessThan&amp;lt;uint&amp;gt;(iterations, 2, &quot;iterations must be greater than or equal to 2&quot;);

    T[] fib = new T[iterations];
    fib[0] = T.Zero;
    fib[1] = T.One;
    for (int i = 2; i &amp;lt; iterations; i++)
    {
        unchecked
        {
            fib[i] = fib[i - 1] + fib[i - 2];
        }
    }

    return fib;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We can sometimes take for granted arithmetic operations and assume they will work. In most cases, they will, but if you’re building mission-critical applications that could run into underflow and overflow situations, it’s better to check these values so as not to cause potential headaches down the line.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and as always, thanks for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 27 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/checked-and-unchecked-arithmetic-operations-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/checked-and-unchecked-arithmetic-operations-in-dotnet</guid>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Confirmation Dialogs with Htmx and SweetAlert</title>
        <description>&lt;p&gt;When building web experiences, there are safe operations and destructive ones. In the case of dangerous actions, it’s widespread to ask the user if they’d like to continue with the action before ultimately executing it.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore a valuable feature in the &lt;a href=&quot;https://htmx.org/events/#htmx:confirm&quot;&gt;Htmx documentation&lt;/a&gt; that allows you to intercept outgoing requests and present a &lt;a href=&quot;https://sweetalert.js.org/guides/&quot;&gt;Sweet Alert confirmation dialog&lt;/a&gt;. This feature can greatly enhance user experience and control in your web applications. Let’s dive in.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-htmxconfirm-event&quot;&gt;The &lt;code&gt;htmx:confirm&lt;/code&gt; event&lt;/h2&gt;

&lt;p&gt;Htmx users are likely familiar with the &lt;code&gt;hx-confirm&lt;/code&gt; attribute, which is a declarative way to use the
&lt;code&gt;confirm&lt;/code&gt; JavaScript function. This uses your browser’s native functionality to display a confirmation dialog that allows the user one last chance to cancel their action.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;button class=&quot;btn btn-danger&quot; 
        hx-post=&quot;&quot;
        name=&quot;input&quot;
        value=&quot;DELETE&quot;
        hx-confirm=&quot;Are you sure?&quot;&amp;gt;
    Delete Important Stuff
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But folks likely don’t know that the &lt;code&gt;htmx:confirm&lt;/code&gt; event is triggered before **every
** request. This allows you to intercept, stop, or continue any Htmx request on the client. This opens up a lot of UX opportunities.&lt;/p&gt;

&lt;p&gt;To register for this event, you will need the following JavaScript referenced in your web application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;document.body.addEventListener(&apos;htmx:confirm&apos;, function (evt) {
    // do something here
    // you can evt.preventDefault()
    // or...
    // evt.details.issueRequest() to continue.
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s use the SweetAlert JavaScript library to enhance the dull confirm dialog.&lt;/p&gt;

&lt;h2 id=&quot;add-sweetalert-to-htmx-confirmations&quot;&gt;Add SweetAlert to Htmx Confirmations&lt;/h2&gt;

&lt;p&gt;I’ll intercept an Htmx request using the event above and slot in a new confirmation dialog. This is the example shown in the Htm documentation. To get started, you’ll need to add a reference to SweetAlert in your web application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;https://unpkg.com/sweetalert/dist/sweetalert.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll need to modify your target elements with the following attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;button class=&quot;btn btn-danger&quot; 
        hx-post=&quot;&quot;
        name=&quot;input&quot;
        value=&quot;DELETE&quot;
        confirm-with-sweet-alert=&apos;true&apos;&amp;gt;
    Delete Important Stuff
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that this attribute is only necessary if you want to be more selective about when and where this new dialog appears. If you aren’t selective, you don’t need this attribute.&lt;/p&gt;

&lt;p&gt;Finally, let’s write some JavaScript code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// site.js
document.body.addEventListener(&apos;htmx:confirm&apos;, function (evt) {
    if (evt.target.matches(&quot;[confirm-with-sweet-alert=&apos;true&apos;]&quot;)) {
        evt.preventDefault();
        swal({
            title: &quot;Are you sure?&quot;,
            text: &quot;Are you sure you are sure?&quot;,
            icon: &quot;warning&quot;,
            buttons: true,
            dangerMode: true,
        }).then((confirmed) =&amp;gt; {
            if (confirmed) {
                evt.detail.issueRequest();
            }
        });
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The event will only be handled when the target element has our
&lt;code&gt;confirm-with-sweet-alert&lt;/code&gt; attribute. Otherwise, it falls back to Htmx’s default behavior.&lt;/p&gt;

&lt;p&gt;Cool! Now, you’ll see the SweetAlert dialog defined in our JavaScript whenever you click the button.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Htmx continues to surprise me with its flexibility and extension points. I recommend reading through more of the documentation to discover more features you can use in your applications. In this case, we can enhance the user experience of dangerous operations to give users more detailed information about the action they are about to take.&lt;/p&gt;

&lt;p&gt;I hope you try this in your applications, and as always, thanks for reading.&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/confirmation-dialogs-with-htmx-and-sweetalert</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/confirmation-dialogs-with-htmx-and-sweetalert</guid>
        
        <category>htmx,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How To Pick The Right Constructor When Using ActivatorUtilities In .NET</title>
        <description>&lt;p&gt;If you’ve ever worked with reflection in .NET, you’re likely familiar with &lt;code&gt;Activator&lt;/code&gt;. In .NET 6, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.activatorutilities?view=net-6.0&quot;&gt;
&lt;code&gt;ActivatorUtilities&lt;/code&gt;&lt;/a&gt; was introduced to make it easier to create classes with dependencies. Constructor dependency injection is common in the .NET space, and you’re likely to run into several types that require constructor parameters before being created. The
&lt;code&gt;Activator&lt;/code&gt; class is a relic of a simpler time, whereas &lt;code&gt;ActivatorUtilities&lt;/code&gt; meets developers where .NET is today.&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at a code example of how to guide
&lt;code&gt;ActivatorUtilities&lt;/code&gt; toward the constructor you want to use when building instances of types that may have multiple constructors.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;registering-a-type-and-the-dependencies&quot;&gt;Registering a Type and the Dependencies&lt;/h2&gt;

&lt;p&gt;Let’s start by looking at a &lt;code&gt;Person&lt;/code&gt; class that has a total of three constructors. Wowza!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Person(string name, int age = 0)
{
    public Person(string name)
        : this(name, 0)
    {
        Console.WriteLine(&quot;Person(string)&quot;);
    }
    
    public Person(object name)
        : this(name.ToString()!, 41)
    {
        Console.WriteLine(&quot;Person(object)&quot;);
    }

    public string Name { get; } = name;
    public int Age { get; } = age;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We have the following constructors.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A primary constructor that takes a name and an optional age&lt;/li&gt;
  &lt;li&gt;A constructor that takes a &lt;code&gt;string&lt;/code&gt; dependency&lt;/li&gt;
  &lt;li&gt;A constructor that takes an &lt;code&gt;object&lt;/code&gt; dependency&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s set up our new
&lt;code&gt;ServiceCollection&lt;/code&gt; and add dependencies to the dependency collection. Note that you’ll need to install the NuGet package
&lt;code&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt; if you haven’t already.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Extensions.DependencyInjection;

var collection = new ServiceCollection();

var value = &quot;Khalid&quot;;

collection.AddTransient&amp;lt;Person&amp;gt;();
// an instance of object
collection.AddSingleton&amp;lt;object&amp;gt;(value);
// an instance of string
collection.AddSingleton&amp;lt;string&amp;gt;(value);

var serviceProvider = collection.BuildServiceProvider();

var person = ActivatorUtilities.CreateInstance&amp;lt;Person&amp;gt;(serviceProvider);

Console.WriteLine($&quot;{person.Name} is {person.Age} years old.&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Take a second and guess what constructor implementation is called. We’ve satisfied all the dependencies, but just by looking at the code, you can feel a sense of uncertainty creeping in. Let’s run it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Khalid is 0 years old.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ah, the primary constructor got called. It makes sense; that’s what “primary” means, right?&lt;/p&gt;

&lt;p&gt;What if we want a different constructor to get called?&lt;/p&gt;

&lt;h2 id=&quot;using-the-activatorutilitiesconstructor-attribute&quot;&gt;Using the ActivatorUtilitiesConstructor Attribute&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt; package, you’ll find the
&lt;code&gt;ActivatorUtilitiesConstructorAttribute&lt;/code&gt;. This attribute gives the
&lt;code&gt;ServiceProvider&lt;/code&gt; hints at which constructor to call first. Let’s modify our
&lt;code&gt;Person&lt;/code&gt; class definition to call the constructor with the &lt;code&gt;object&lt;/code&gt; dependency.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Person(string name, int age = 0)
{
    public Person(string name)
        : this(name, 0)
    {
        Console.WriteLine(&quot;Person(string)&quot;);
    }
    
    [ActivatorUtilitiesConstructor]
    public Person(object name)
        : this(name.ToString()!, 41)
    {
        Console.WriteLine(&quot;Person(object)&quot;);
    }

    public string Name { get; } = name;
    public int Age { get; } = age;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After rerunning our code, we’ll get the following output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Person(object)
Khalid is 41 years old.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we did not change the executing code; we only added a single attribute. With this knowledge, you can now have all the constructors you want on your types but still make it clear which constructor you’d like
&lt;code&gt;ActivatorUtilities&lt;/code&gt; to use.&lt;/p&gt;

&lt;p&gt;There you have it. I hope you enjoyed this post. As always, thanks for reading and sharing with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-pick-the-right-constructor-when-using-activatorutilities-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-pick-the-right-constructor-when-using-activatorutilities-in-dotnet</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Add a Property to the Top-level Statements Program class</title>
        <description>&lt;p&gt;The evolution of the C# language has introduced us to many new features and probably made a lot of folks re-evaluate how they write their apps. In the latest versions of .NET, nothing has been marked such a stylistic shift as the introduction of top-level statements.&lt;/p&gt;

&lt;p&gt;In this short post, we’ll examine how to add properties to your &lt;code&gt;Program&lt;/code&gt; instance to improve the readability of utility console applications.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;top-level-statement-files&quot;&gt;Top-level statement files&lt;/h2&gt;

&lt;p&gt;When starting a new console application, you can create a &lt;code&gt;Program.cs&lt;/code&gt; file and opt into the top-level statements style. The single line below is a valid .NET application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Console.WriteLine(&quot;Hello, World&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At compile-time, the compiler generates the typical ceremony associated with traditional applications. Looking at our app’s low-level C# version, we’ll see the symbols we typically expect to see in a .NET app.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void &amp;lt;Main&amp;gt;$(string[] args)
  {
    Console.WriteLine(&quot;Hello, World&quot;);
  }

  public Program()
  {
    base..ctor();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll see that there is always a &lt;code&gt;Program&lt;/code&gt; class and the expected entry point of &lt;code&gt;static void Main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s get more complex.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Console.WriteLine($&quot;Hello, {GetName()}&quot;);  
  
string GetName()  
{  
    return Environment.GetCommandLineArgs()[1];  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does this look like now?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void &amp;lt;Main&amp;gt;$(string[] args)
  {
    Console.WriteLine(string.Concat(&quot;Hello, &quot;, Program.&amp;lt;&amp;lt;Main&amp;gt;$&amp;gt;g__GetName|0_0()));
  }

  public Program()
  {
    base..ctor();
  }

  [NullableContext(1)]
  [CompilerGenerated]
  internal static string &amp;lt;&amp;lt;Main&amp;gt;$&amp;gt;g__GetName|0_0()
  {
    return Environment.GetCommandLineArgs()[1];
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The method attached to the end of the file becomes an internal static method on the Program. Can we add a property? In this case, a property would be much more readable than a method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// not valid c#
Console.WriteLine($&quot;Hello, {Name}&quot;);  
  
string Name =&amp;gt; Environment.GetCommandLineArgs()[1];
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;This syntax does not work.&lt;/strong&gt; Still, we can add a &lt;code&gt;Name&lt;/code&gt; property to our &lt;code&gt;Program&lt;/code&gt; file.&lt;/p&gt;

&lt;h2 id=&quot;adding-the-property-with-a-partial-class&quot;&gt;Adding the property with a partial class&lt;/h2&gt;

&lt;p&gt;How do we get top-level properties into our top-level statements file? Well, it’s pretty straightforward. The &lt;code&gt;Program&lt;/code&gt; class can be extended using the &lt;code&gt;partial&lt;/code&gt; keyword. Let’s do that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Console.WriteLine($&quot;Hello, {Name}&quot;);

partial class Program
{
    static string Name =&amp;gt; Environment.GetCommandLineArgs()[1];    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we can add scoped properties to our top-level statement files. Returning to our low-level C#, we can see what the compiler is doing.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using System.Runtime.CompilerServices;

internal class Program
{
  private static void &amp;lt;Main&amp;gt;$(string[] args)
  {
    Console.WriteLine(string.Concat(&quot;Hello, &quot;, Program.Name));
  }

  [Nullable(1)]
  private static string Name
  {
    [NullableContext(1)] get
    {
      return Environment.GetCommandLineArgs()[1];
    }
  }

  public Program()
  {
    base..ctor();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also move your partial &lt;code&gt;Program&lt;/code&gt; class to another file if you are going for that minimal aesthetic entry point look. One thing to note is that all properties must be &lt;code&gt;static&lt;/code&gt;, as the properties are referenced in the &lt;code&gt;static void Main&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I hope this post helps, and as always, thanks for reading. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/add-a-property-to-the-top-level-statements-program-class</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/add-a-property-to-the-top-level-statements-program-class</guid>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Fix .NET MAUI MissingEntitlement and Provisioning Profiles Issues</title>
        <description>&lt;p&gt;There are times on this blog when I write posts for the reader’s benefit and times when I need to memorialize my own
pain and suffering to find a solution to a seemingly simple issue. This post is the latter.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see what it takes to fix the &lt;code&gt;MissingEntitlement&lt;/code&gt; and “Could not find any available provisioning
profiles” errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Also, be warned: You might not like what you see.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ok, let’s go!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;ios-security-and-entitlements&quot;&gt;iOS, Security, and Entitlements&lt;/h2&gt;

&lt;p&gt;I recently purchased the &lt;a href=&quot;https://www.manning.com/books/dot-net-maui-in-action&quot;&gt;“.NET MAUI in Action” book&lt;/a&gt; and was working
through the sample application in Chapter 3. The author’s
perspective differs from mine in that their app targets Windows, and I am targeting iOS. As one might expect, the
details between the two target platforms differ.&lt;/p&gt;

&lt;p&gt;This difference led to my first issue running the sample application targeting iOS; I got this exception and crashed the
application.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;System.Exception: Error adding record: MissingEntitlement
   at Microsoft.Maui.Storage.KeyChain.SetValueForKey(String value, String key, String service)
   at Microsoft.Maui.Storage.SecureStorageImplementation.SetAsync(String key, String value, SecAccessible accessible)
   at Microsoft.Maui.Storage.SecureStorageImplementation.PlatformSetAsync(String key, String data)
   at Microsoft.Maui.Storage.SecureStorageImplementation.SetAsync(String key, String value)
   at Microsoft.Maui.Storage.SecureStorage.SetAsync(String key, String value)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This leads users to the first issue, a missing &lt;code&gt;Entitlements.plist&lt;/code&gt; file. What are Entitlements?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Side Note: The &lt;code&gt;MissingEntitlment&lt;/code&gt; exception could really use a more helpful error message. WHICH ONE MAUI? WHICH
ONE?!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All iOS applications are sandboxed, allowing the app only to execute iOS functions it has requested and explicitly been
granted by the user. Entitlements ensure apps behave as intended and don’t expose users to unnecessary risks. For your
application to use iOS features like Maps, KeyChain, or Siri, you must first add values to the &lt;code&gt;Entitlements.plist&lt;/code&gt; file
to request access. Only then can you use these features.&lt;/p&gt;

&lt;p&gt;You can read more
about &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/maui/ios/entitlements?view=net-maui-8.0&amp;amp;tabs=vs#add-an-entitlementsplist-file&quot;&gt;Entitlements on the Microsoft documentation site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Side Note: I would think the .NET MAUI template would have an empty entitlements file already in the &lt;code&gt;Platforms/iOS&lt;/code&gt;
folder, but
it
doesn’t.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, in the &lt;code&gt;Platforms/iOS&lt;/code&gt; folder, you’ll need to create an &lt;code&gt;Entitlements.plist&lt;/code&gt;file with the following XML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
    &amp;lt;dict&amp;gt;
    &amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For enabling the Maps feature, your &lt;code&gt;Entitlements.plist&lt;/code&gt; file might look like the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
    &amp;lt;dict&amp;gt;
        &amp;lt;key&amp;gt;com.apple.developer.maps&amp;lt;/key&amp;gt;
        &amp;lt;true/&amp;gt;
    &amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also use &lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider’s&lt;/a&gt; plist editor to create and manage these files with
schema validation and an excellent UI experience.&lt;/p&gt;

&lt;p&gt;You should be good to go, right? Not so fast. Running your application now presents you with the following error.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1&amp;gt;Xamarin.Shared.targets(1820,3): Error  : Could not find any available provisioning profiles for MauiTodo on iOS.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wait…. what?! What’s going on? I’m only trying to deploy to the iOS simulator!&lt;/p&gt;

&lt;h2 id=&quot;provisioning-profiles-apple-developer-account-and-physical-devices&quot;&gt;Provisioning Profiles, Apple Developer Account, and Physical Devices&lt;/h2&gt;

&lt;p&gt;Adding the &lt;code&gt;Entitlements.plist&lt;/code&gt; file has cascaded into a secondary issue in the build process. (Note that I’m currently
using .NET 8.0 and 9.0 workloads).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1&amp;gt;Xamarin.Shared.targets(1820,3): Error  : Could not find any available provisioning profiles for MauiTodo on iOS.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;MAUI is looking for a provisioning profile. What is a provisioning profile?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A &lt;em&gt;development provisioning profile&lt;/em&gt; allows your app to launch on devices and use certain app services during
development. For an individual, a development provisioning profile allows apps signed by you to run on your registered
devices. For an organization, a development provisioning profile allows apps developed by a team to be signed by any
member of the team and installed on their
devices. –&lt;a href=&quot;https://developer.apple.com/help/account/manage-profiles/create-a-development-provisioning-profile&quot;&gt;Apple&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Huh. How do you fix this issue? I just want to deploy my app to my local simulator.&lt;/p&gt;

&lt;p&gt;Here are the steps you’ll need to fix this, and I’ll start with the two most significant hurdles.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A physical iOS device. &lt;strong&gt;Yes, you will need a physical device.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;An Apple Developer Account at $99/year. &lt;a href=&quot;https://developer.apple.com/&quot;&gt;Sign up here&lt;/a&gt; or give up now.&lt;/li&gt;
  &lt;li&gt;macOS and XCode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First, Be sure to
enable &lt;a href=&quot;https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device&quot;&gt;Developer Mode&lt;/a&gt; on your
device. You’ll need the identifier for this physical device. To get your device’s UUID, connect your iOS device to your
macOS machine and launch XCode. Open “Window | Devices and Simulators.” Here, you’ll see your device’s ID. You’ll need
this to register the device.&lt;/p&gt;

&lt;p&gt;Log in to your new Apple Developer account and add your physical device. You
can &lt;a href=&quot;https://developer.apple.com/account/resources/devices/add&quot;&gt;visit the “Register a New Device” page.&lt;/a&gt; Here, you’ll
register the physical device, at which point you’ll get a provisioning profile.&lt;/p&gt;

&lt;p&gt;Now, open your MAUI project in XCode (which you can do from JetBrains Rider). Under the Project settings’ “Signing &amp;amp;
Capabilities” tab, select a Team and check the &lt;strong&gt;Automatically manage signing&lt;/strong&gt; checkbox. If you don’t see a Team, be
sure to add your Apple Developer account to Xcode under “Settings | Accounts” and try again.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/misc/maui-xcode-provisioing-profile-certificate.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;Xcode showing provisioning profile&quot; loading=&quot;lazy&quot; width=&quot;1742&quot; height=&quot;738&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If all goes well, you should see values for the Provisioning Profiles and Signing Certificate fields in the bottom iOS
section.&lt;/p&gt;

&lt;p&gt;Now, you can go back to building and deploying your application with Entitlements to the iOS simulator without any
issues. Xcode will handle signing your apps from here on out.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The steps outlined here fixed my issue, but honestly, it took way longer and a significant amount of money 💰 to solve
this issue, given the price of a physical iOS device and an Apple Developer subscription. I am still not sure if this is
an Xcode and iOS issue or a &lt;a href=&quot;https://github.com/dotnet/maui/issues/19148&quot;&gt;MAUI issue&lt;/a&gt;. All I know is that it’s a MAUI
developer stumbling block that I ran into, and it’s now “solved.”&lt;/p&gt;

&lt;p&gt;I hope this post helps you on your MAUI development journey. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/fix-dotnet-maui-missingentitlement-and-provisioning-profiles-issues</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/fix-dotnet-maui-missingentitlement-and-provisioning-profiles-issues</guid>
        
        <category>maui,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Health Checks for ASP.NET Core and Entity Framework Core</title>
        <description>&lt;p&gt;I’ve recently been reading up on .NET Aspire and have found a lot of cool .NET tech underpinning the offering. One of
the tools that has gotten a glow-up since I last looked at it has been &lt;code&gt;Microsoft.Extensions.Diagnostics.HealthChecks&lt;/code&gt;
package provides you with the infrastructure to perform various types of system health monitoring.&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at installing the health checks package into existing ASP.NET Core applications and using an
additional package to perform health checks on your databases using Entity Framework Core.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;install-and-set-up-health-checks&quot;&gt;Install and Set Up Health Checks&lt;/h2&gt;

&lt;p&gt;In an existing ASP.NET Core application, you’ll need to install the following package.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the package has been installed, you must do several setup tasks in your &lt;code&gt;Program&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The first step is to register the &lt;code&gt;HealthChecks&lt;/code&gt; middleware and services in the services collection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddHealthChecks();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, in your ASP.NET Core request pipeline, you’ll need to register the middleware. You can choose whether to place the
middleware before or after the authorization middleware, but as you’ll see, there might not be much reason to have this
behind an auth check.&lt;/p&gt;

&lt;p&gt;You’ll need to choose a URL path to access your health check. I used the &lt;code&gt;/health&lt;/code&gt; path for this case, but feel free to
choose whatever suits you.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.UseRouting();

app.UseHealthChecks(&quot;/health&quot;);

app.UseAuthorization();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Navigating to the &lt;code&gt;/health&lt;/code&gt; endpoint will get you the following response.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The response will always be a string of &lt;code&gt;Healthy&lt;/code&gt;, &lt;code&gt;Unhealthy&lt;/code&gt;, or &lt;code&gt;Degraded&lt;/code&gt;. This makes it simple for third-party
health check systems to determine your application’s general health quickly. Your logging system will handle the details
of the issues.&lt;/p&gt;

&lt;p&gt;Let’s write a new health check! You’ll need to implement the &lt;code&gt;IHealthCheck&lt;/code&gt; interface and implement the
&lt;code&gt;CheckHealthAsync&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace Healthnut.Services;

public class KhalidHealthCheck: IHealthCheck
{
    public Task&amp;lt;HealthCheckResult&amp;gt; CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken())
    {
        return Task.FromResult(
            HealthCheckResult.Degraded(&quot;Khalid ate some ice cream&quot;)
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These classes are added to your services collection, so they can opt-in to any dependency injection mechanisms you might
want to use. Let’s add it to our health checks. Modify the registration in the &lt;code&gt;Program&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services
    .AddHealthChecks()
    .AddCheck&amp;lt;KhalidHealthCheck&amp;gt;(&quot;Khalid&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that health checks require a unique name. You’ll see a &lt;code&gt;Degraded&lt;/code&gt; string after rerunning the app and hitting the
&lt;code&gt;/health&lt;/code&gt; endpoint. What’s more interesting is that you’ll see a new log message on your terminal.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;warn: Microsoft.Extensions.Diagnostics.HealthChecks.DefaultHealthCheckService[103]
      Health check Khalid with status Degraded completed after 2.5366ms with message &apos;Khalid ate some ice cream&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Health checks are &lt;code&gt;async&lt;/code&gt;, so you can write any logic you need to determine the health of your system, but be sure it’s
snappy and non-resource-intensive checks; otherwise, ironically, the health checks could lead to unhealthy results.&lt;/p&gt;

&lt;p&gt;If you hate the formalities of classes and interfaces, you can also choose to implement health checks directly at the
point of registration. This can be helpful for microservices or smaller utility applications.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services
    .AddHealthChecks()
    .AddCheck&amp;lt;KhalidHealthCheck&amp;gt;(&quot;Khalid&quot;)
    .AddAsyncCheck(&quot;Butter&quot;, async () =&amp;gt;
    {
        await Task.Delay(1000);
        return new HealthCheckResult(HealthStatus.Healthy, &quot;Butter is good&quot;);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, it’s been good, but let’s now use health checks for our database.&lt;/p&gt;

&lt;h2 id=&quot;health-checks-for-entity-framework-core&quot;&gt;Health checks for Entity Framework Core&lt;/h2&gt;

&lt;p&gt;You’ll need to install a new package to get a new extension method for EF Core health checks. You should already have an
Entity Framework Core application with a &lt;code&gt;DbContext&lt;/code&gt; implementation. If you don’t, create one. Now, the package.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once installed, we can update our health check registration using the following line.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services
    .AddHealthChecks()
    .AddCheck&amp;lt;KhalidHealthCheck&amp;gt;(&quot;Khalid&quot;)
    .AddAsyncCheck(&quot;Butter&quot;, async () =&amp;gt;
    {
        await Task.Delay(1000);
        return new HealthCheckResult(HealthStatus.Healthy, &quot;Butter is good&quot;);
    })
    .AddDbContextCheck&amp;lt;Database&amp;gt;(
        &quot;people check&quot;,
        customTestQuery: (db, token) =&amp;gt; db.People.AnyAsync(token)
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;AddDbContextCheck&lt;/code&gt; takes a generic argument of a &lt;code&gt;DbContext&lt;/code&gt; implementation, and the &lt;code&gt;customTestQuery&lt;/code&gt; argument is
a query you can execute to verify the health of your database. The provided query must return a single &lt;code&gt;bool&lt;/code&gt; value. Use
logical LINQ operators such as &lt;code&gt;Any&lt;/code&gt; and &lt;code&gt;All&lt;/code&gt;, or write queries that evaluate entirely on the server with limited
results returned. Oh, and keep these queries snappy and to the point. Doing expensive database checks may impact the
health of your application.&lt;/p&gt;

&lt;p&gt;Rerunning the application, we’ll see the log message we expect.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (14ms) [Parameters=[], CommandType=&apos;Text&apos;, CommandTimeout=&apos;30&apos;]
      SELECT EXISTS (
          SELECT 1
          FROM &quot;People&quot; AS &quot;p&quot;)
fail: Microsoft.Extensions.Diagnostics.HealthChecks.DefaultHealthCheckService[103]
      Health check people check with status Unhealthy completed after 1545.2538ms with message &apos;(null)&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We barely scratched the surface of what’s possible with the health checks feature of ASP.NET Core, and there’s so much
more you can do to provide real-time health updates of your applications. There’s also a wide variety of health check
extensions on NuGet, so you’ll rarely have to write your own, but it’s nice knowing you could with such a
straightforward interface.&lt;/p&gt;

&lt;p&gt;Finally, It’s important to remember that you’ll need a monitoring tool to watch these endpoints to get the most out of
them, but I’ll leave that decision up to you.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/health-checks-for-aspnet-core-and-entity-framework-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/health-checks-for-aspnet-core-and-entity-framework-core</guid>
        
        <category>aspnet,</category>
        
        <category>efcore</category>
        
        
      </item>
    
      <item>
        <title>How To Fix .NET Nullability Warnings For Guarded Members</title>
        <description>&lt;p&gt;Nullability provides developers with development-time warnings that can help reduce dereferencing issues. These errors
can be costly, but with the power of a few additional checks in code, developers can easily avoid them, putting them in
control of their code’s quality.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see a code sample that should be “safe” yet continues to give IDE and build-time warnings about
dereferencing of a possibly null reference. We’ll also see how to adjust your code to remove unnecessary warnings in
current and future projects.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;dereference-of-a-possibly-null-reference&quot;&gt;Dereference of a possibly null reference&lt;/h2&gt;

&lt;p&gt;Let’s look at some basic C# code, which you likely have something similar to in your projects.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var database = new Database();

// Name cannot be null when Initialize is true
if (database.Initialized)
{
    // This has a warning about Name being null
    var length = database.Name.Length;
    
    Console.WriteLine($&quot;{database.Name} and length is {length}&quot;);
}

Console.WriteLine(&quot;Hello, World!&quot;);

public class Database
{
    public string? Name { get; set; }
    public bool Initialized =&amp;gt; Name is not null;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we have a &lt;code&gt;Database&lt;/code&gt; class, and we know the &lt;code&gt;Name&lt;/code&gt; property will never be &lt;code&gt;null&lt;/code&gt; if the boolean property of
&lt;code&gt;Initialized&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt;. Yet, you likely see a yellow line warning you with the message “Dereference of a possibly
null reference” in your editor. Additionally, this warning shows up in your build logs.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Program.cs(9,18): Warning CS8602 : Dereference of a possibly null reference.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can ignore this, right? Well, not if your team uses the MSBuild element of &lt;code&gt;TreatWarningsAsErrors&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&amp;gt;

    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;OutputType&amp;gt;Exe&amp;lt;/OutputType&amp;gt;
        &amp;lt;TargetFramework&amp;gt;net9.0&amp;lt;/TargetFramework&amp;gt;
        &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
        &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
        &amp;lt;TreatWarningsAsErrors&amp;gt;true&amp;lt;/TreatWarningsAsErrors&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

&amp;lt;/Project&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh no! Our build is broken!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;0&amp;gt;Program.cs(9,18): Error CS8602 : Dereference of a possibly null reference.
0&amp;gt;------- Finished building project: ConsoleApp2. Succeeded: False. Errors: 1. Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How do we fix this?&lt;/p&gt;

&lt;h2 id=&quot;using-membernotnullwhen-on-boolean-properties&quot;&gt;Using MemberNotNullWhen On Boolean Properties&lt;/h2&gt;

&lt;p&gt;There are several attributes under the &lt;code&gt;System.Diagnostics.CodeAnalysis&lt;/code&gt; namespace that we can use to give the compiler
hints about the safety of the written code. The attribute we’ll use is &lt;code&gt;MemberNotNullWhen&lt;/code&gt;, which allows us to decorate
a property or method that returns a &lt;code&gt;bool&lt;/code&gt; result and tie the safety check to one or more other properties.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Diagnostics.CodeAnalysis;

var database = new Database();

// Name cannot be null when Initialize is true
if (database.Initialized)
{
    // The warning/error is now gone
    var length = database.Name.Length;
    
    Console.WriteLine($&quot;{database.Name} and length is {length}&quot;);
}

Console.WriteLine(&quot;Hello, World!&quot;);

public class Database
{
    public string? Name { get; set; }
    // this attribute fixes the issue
    [MemberNotNullWhen(true, nameof(Name))]
    public bool Initialized =&amp;gt; Name is not null;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The steps in the code are as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Decorate a boolean property or method that returns &lt;code&gt;bool&lt;/code&gt; with &lt;code&gt;MemberNotNullWhen&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Choose the value state that signals safety to the compiler.&lt;/li&gt;
  &lt;li&gt;Choose one or more nullable members covered by the &lt;code&gt;bool&lt;/code&gt; member.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There should be no editor warnings or build errors, and you can live the good life. I hope you found this post helpful.
As always, thank you for reading. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-fix-dotnet-nullability-warnings-for-guarded-members</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-fix-dotnet-nullability-warnings-for-guarded-members</guid>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>HTML Datalist for ASP.NET Core Inputs</title>
        <description>&lt;p&gt;In my last blog post, I discussed range inputs. This time, we’ll examine a tag helper that adds support for the HTML element of &lt;code&gt;datalist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this short post, I’ll explain what a &lt;code&gt;datalist&lt;/code&gt; is and why you may want to consider using it in your ASP.NET Core applications. Finally, we’ll implement a set of tag helpers to make using the &lt;code&gt;datalist&lt;/code&gt; element more straightforward with your ASP.NET Core MVC and Razor Page applications.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-datalist&quot;&gt;What is &lt;code&gt;datalist&lt;/code&gt;?&lt;/h2&gt;

&lt;p&gt;True to its name, the &lt;code&gt;datalist&lt;/code&gt; element allows web developers to create a list of options that are permissible or recommended for form input elements. This allows users to choose from a predefined list the application developer has curated.&lt;/p&gt;

&lt;p&gt;Let’s look at a quick HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist#browser_compatibility&quot;&gt;example pulled from the MDN web docs&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;label for=&quot;ice-cream-choice&quot;&amp;gt;Choose a flavor:&amp;lt;/label&amp;gt;
&amp;lt;input list=&quot;ice-cream-flavors&quot; id=&quot;ice-cream-choice&quot; name=&quot;ice-cream-choice&quot;/&amp;gt;

&amp;lt;datalist id=&quot;ice-cream-flavors&quot;&amp;gt;
    &amp;lt;option value=&quot;Chocolate&quot;&amp;gt;&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;Coconut&quot;&amp;gt;&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;Mint&quot;&amp;gt;&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;Strawberry&quot;&amp;gt;&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;Vanilla&quot;&amp;gt;&amp;lt;/option&amp;gt;
&amp;lt;/datalist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;ice-cream-choice&lt;/code&gt; field will use the &lt;code&gt;datalist&lt;/code&gt; options and provide users with a dropdown of potential options but still allow users to type their choices using freeform text.&lt;/p&gt;

&lt;p&gt;The list attribute supports multiple input types, including &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, and &lt;code&gt;color&lt;/code&gt;. While the &lt;code&gt;datalist&lt;/code&gt; is supported in most browsers, Firefox partially supports the input field and does not work with the types &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, and &lt;code&gt;color&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Providing a &lt;code&gt;datalist&lt;/code&gt; can guide your users to common answers for otherwise fuzzy fields. The element might be helpful in surveys or support forms.&lt;/p&gt;

&lt;p&gt;How do we use it in ASP.NET Core MVC and Razor Pages?&lt;/p&gt;

&lt;h2 id=&quot;datalist-taghelper-for-mvc-and-razor-pages&quot;&gt;Datalist TagHelper for MVC and Razor Pages&lt;/h2&gt;

&lt;p&gt;Let’s start with our end goal of using a &lt;code&gt;datalist&lt;/code&gt; in our Razor views. We’ll look at a Razor Pages example where we’ll see the HTML and C# Page Model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace OutputValues.Pages;

public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    [BindProperty]
    public string? Value { get; set; }

    public string? Message { get; set; }

    public List&amp;lt;SelectListItem&amp;gt; Fruits { get; } =
    [
        new(&quot;The finest from Tokyo&quot;, &quot;Apple&quot;),
        new(&quot;The curviest fruit&quot;, &quot;Banana&quot;),
        new(&quot;The citrus is amazing&quot;, &quot;Orange&quot;)
    ];

    public void OnGet()
    {
    }

    public void OnPost()
    {
        Message = $&quot;You selected {Value}!&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll reuse the &lt;code&gt;SelectListItem&lt;/code&gt; class commonly used by the select element. There’s no reason to reinvent the wheel here. Next, let’s update our view.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;form method=&quot;post&quot; asp-page=&quot;Index&quot;&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;label class=&quot;form-label&quot; asp-for=&quot;Value&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;input class=&quot;form-control&quot; asp-for=&quot;Value&quot; asp-list=&quot;Fruits&quot; /&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;button type=&quot;submit&quot; class=&quot;mt-3 btn btn-primary&quot;&amp;gt;
        Add
    &amp;lt;/button&amp;gt;
    
    &amp;lt;datalist asp-items=&quot;Fruits&quot;&amp;gt;&amp;lt;/datalist&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it! We now have an input field backed by our new &lt;code&gt;datalist&lt;/code&gt;. Let’s see what the output HTML looks like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;form method=&quot;post&quot; action=&quot;/&quot;&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;label class=&quot;form-label&quot; for=&quot;Value&quot;&amp;gt;Value&amp;lt;/label&amp;gt;
        &amp;lt;input class=&quot;form-control&quot; type=&quot;text&quot; id=&quot;Value&quot; name=&quot;Value&quot; value=&quot;&quot; list=&quot;Fruits&quot;&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;button type=&quot;submit&quot; class=&quot;mt-3 btn btn-primary&quot;&amp;gt;
        Add
    &amp;lt;/button&amp;gt;

    &amp;lt;datalist id=&quot;Fruits&quot;&amp;gt;
        &amp;lt;option label=&quot;The finest from Tokyo&quot; value=&quot;Apple&quot;&amp;gt;&amp;lt;/option&amp;gt;
        &amp;lt;option label=&quot;The curviest fruit&quot; value=&quot;Banana&quot;&amp;gt;&amp;lt;/option&amp;gt;
        &amp;lt;option label=&quot;The citrus is amazing&quot; value=&quot;Orange&quot;&amp;gt;&amp;lt;/option&amp;gt;
    &amp;lt;/datalist&amp;gt;
    &amp;lt;input name=&quot;__RequestVerificationToken&quot; type=&quot;hidden&quot; value=&quot;&quot;&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The tag helpers are designed to look for &lt;code&gt;asp-items&lt;/code&gt; on a &lt;code&gt;datalist&lt;/code&gt; element and an &lt;code&gt;asp-list&lt;/code&gt; attribute on any input field. Let’s see how these two tag helpers are implemented.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace OutputValues;

[HtmlTargetElement(&quot;datalist&quot;, Attributes = ItemsAttributeName)]
public class DataListHelper : TagHelper
{
    private const string ItemsAttributeName = &quot;asp-items&quot;;

    /// &amp;lt;summary&amp;gt;
    /// A collection of &amp;lt;see cref=&quot;SelectListItem&quot;/&amp;gt; objects used to populate the &amp;amp;lt;datalist&amp;amp;gt; element with
    /// &amp;amp;lt;option&amp;amp;gt; elements.
    /// &amp;lt;/summary&amp;gt;
    [HtmlAttributeName(ItemsAttributeName)]
    public ModelExpression For { get; set; } = default!;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        ArgumentNullException.ThrowIfNull(context);
        ArgumentNullException.ThrowIfNull(output);

        var items = (IEnumerable&amp;lt;SelectListItem&amp;gt;)For.Model ?? [];
        foreach (var item in items)
        {
            var tagBuilder = new TagBuilder(&quot;option&quot;)
            {
                Attributes =
                {
                    [&quot;value&quot;] = item.Value
                }
            };

            if (!string.IsNullOrWhiteSpace(item.Text))
            {
                tagBuilder.Attributes[&quot;label&quot;] = item.Text;
            }

            output.PostContent.AppendHtml(tagBuilder);
        }

        // the developer may choose their own id if they choose to
        // otherwise we use the property name to generate an id
        if (!output.Attributes.ContainsName(&quot;id&quot;))
        {
            var id = GetDatalistId(For);
            output.Attributes.SetAttribute(&quot;id&quot;, id);
        }
    }

    public static string GetDatalistId(ModelExpression @for)
    {
        // perhaps we want different ids
        return TagBuilder.CreateSanitizedId(@for.Name, &quot;&quot;);
    }
}

[HtmlTargetElement(&quot;input&quot;, Attributes = ItemsAttributeName)]
public class DataListInputHelper : TagHelper
{
    private const string ItemsAttributeName = &quot;asp-list&quot;;

    /// &amp;lt;summary&amp;gt;
    /// A collection of &amp;lt;see cref=&quot;SelectListItem&quot;/&amp;gt; objects used to populate the &amp;amp;lt;datalist&amp;amp;gt; element with
    /// &amp;amp;lt;option&amp;amp;gt; elements.
    /// &amp;lt;/summary&amp;gt;
    [HtmlAttributeName(ItemsAttributeName)]
    public ModelExpression For { get; set; } = default!;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        ArgumentNullException.ThrowIfNull(context);
        ArgumentNullException.ThrowIfNull(output);

        // if it already has a list attribute then don&apos;t override it
        // not sure why it&apos;s there, but sure why not 🤷‍♂️
        if (!output.Attributes.ContainsName(&quot;list&quot;))
        {
            var listId = DataListHelper.GetDatalistId(For);
            output.Attributes.SetAttribute(&quot;list&quot;, listId);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This straightforward implementation could easily be modified to accommodate your needs.&lt;/p&gt;

&lt;p&gt;The most crucial implementation detail is the &lt;code&gt;ModelExpression&lt;/code&gt;, which allows us to get both the metadata of our property and the value of the property. It’s an awesome part of the tag helper API.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;datalist&lt;/code&gt; element is an HTML-native feature that provides completion on several input types. With a few simple tag helpers, we can derive the &lt;code&gt;datalist&lt;/code&gt; options we need to power any input, thus reducing the work required to keep the UI and application data models in sync. Please try this and let me know if you found it helpful.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading, and cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/html-datalist-for-aspnet-core-inputs</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/html-datalist-for-aspnet-core-inputs</guid>
        
        <category>aspnet,</category>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>HTML Range Inputs with ASP.NET Core TagHelpers</title>
        <description>&lt;p&gt;I’ve recently been rediscovering all the input fields that HTML offers and how they can help developers build more straightforward user experiences. The library of native HTML controls is impressive, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input&quot;&gt;with 22 HTML input types&lt;/a&gt; as of this post.&lt;/p&gt;

&lt;p&gt;Looking through ASP.NET Core’s &lt;code&gt;InputTagHelper&lt;/code&gt;, I counted 14 supported input types based on the .NET common language runtime types you may use in your models. That’s over 8 controls missing from ASP.NET Core. The missing &lt;code&gt;range&lt;/code&gt; input is one of the most valuable controls.&lt;/p&gt;

&lt;p&gt;In this post, we’ll write an ASP.NET Core tag helper that piggybacks on the &lt;code&gt;InputTagHelper&lt;/code&gt; and turns a number property into a range input.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-the-range-input&quot;&gt;What is the &lt;code&gt;range&lt;/code&gt; Input?&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;range&lt;/code&gt; input is as it sounds. Developers commonly refer to these elements as a “slider” since users typically slide an indicator to set a value. The input allows users to choose a value constrained by a minimum and maximum value. The limitation ensures that users can only choose valid values. When defining a range input, you may specify the &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, and &lt;code&gt;step&lt;/code&gt; attributes. You may also provide markers along the slider path in the form of a &lt;code&gt;datalist&lt;/code&gt;. It is a very powerful control.&lt;/p&gt;

&lt;p&gt;I highly recommend reading &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range&quot;&gt;the MDN on the topic&lt;/a&gt; to learn more details.&lt;/p&gt;

&lt;h2 id=&quot;taghelper-piggyback-to-slider&quot;&gt;TagHelper Piggyback to Slider&lt;/h2&gt;

&lt;p&gt;When working with ASP.NET Core MVC or Razor Pages, you’ll typically have a model and a razor view. Let’s examine both. First, the page model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    [BindProperty]
    public int Value { get; set; }
    
    public string? Message { get; set; }
    
    public void OnGet()
    {
    }

    public void OnPost()
    {
        Message = $&quot;You selected {Value}!&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, the Razor view.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page
@model IndexModel
@{
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;
}

@if (Model.Message is not null)
{
    &amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
        @Model.Message
    &amp;lt;/div&amp;gt;
}

&amp;lt;form method=&quot;post&quot; asp-page=&quot;Index&quot;&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;label class=&quot;form-label&quot; asp-for=&quot;Value&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;input class=&quot;form-range&quot; asp-for=&quot;Value&quot; /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&amp;gt;
        Add
    &amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, so good, but when you run this application, you’ll notice that the input type for our &lt;code&gt;Value&lt;/code&gt; field is set to &lt;code&gt;text&lt;/code&gt;. It’s not what we want, let’s fix that.&lt;/p&gt;

&lt;p&gt;The first step is using the &lt;code&gt;RangeAttribute&lt;/code&gt; and creating a derived &lt;code&gt;RangeWithStepAttribute&lt;/code&gt; for additional metadata. You could also create separate attributes for additional metadata. The choice is yours.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class RangeWithStepAttribute(int minimum, int maximum)
    : RangeAttribute(minimum, maximum)
{
    public double Step { get; set; } = 1;
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s decorate our property with the new attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[BindProperty, RangeWithStep(1, 5, Step = 1)]
public int Value { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, so good; now let’s create a tag helper that recognizes the &lt;code&gt;RangeAttribute&lt;/code&gt; on our models.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using OutputValues.Pages;

namespace OutputValues;

[HtmlTargetElement(&quot;input&quot;, 
    Attributes = ForAttributeName, 
    TagStructure = TagStructure.WithoutEndTag)]
public class RangeInputTagHelper : TagHelper
{
    private const string ForAttributeName = &quot;asp-for&quot;;
    private const string TypeAttributeValue = &quot;range&quot;;

    public override int Order { get; } = -999;

    [HtmlAttributeName(ForAttributeName)] public ModelExpression For { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var metadata = For.Metadata;

        if (metadata is { ContainerType: not null, PropertyName: not null })
        {
            var attribute =
                metadata.ContainerType.GetProperty(metadata.PropertyName)
                ?.GetCustomAttributes(typeof(RangeAttribute), true)
                .FirstOrDefault();
            
            if (attribute is RangeAttribute range)
            {
                output.Attributes.SetAttribute(&quot;type&quot;, TypeAttributeValue);
                output.Attributes.SetAttribute(&quot;min&quot;, range.Minimum);
                output.Attributes.SetAttribute(&quot;max&quot;, range.Maximum);

                if (range is RangeWithStepAttribute rws)
                {
                    output.Attributes.SetAttribute(&quot;step&quot;, rws.Step);
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All we need to do is register our custom tag helper in the &lt;code&gt;_ViewImports.cshtml&lt;/code&gt;. Change the assembly name to match your assembly name.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@addTagHelper *, OutputValues
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A note about the &lt;code&gt;Order&lt;/code&gt; property on the &lt;code&gt;RangeInputTagHelper&lt;/code&gt; and why it’s set to &lt;code&gt;-999&lt;/code&gt;. The default &lt;code&gt;InputTagHelper&lt;/code&gt; has a value of &lt;code&gt;-1000&lt;/code&gt;, meaning it will likely run before all tag helpers you create. Typically, the order doesn’t matter too much, but in this case, we want our tag helper to do as little work as possible, letting the original tag helper do much of the work it typically does. Since HTML inputs share a lot of attributes and behaviors, this is ideal for this scenario. We set our tag helper to &lt;code&gt;-999&lt;/code&gt; to ensure it runs sometime right after the original tag helper.&lt;/p&gt;

&lt;p&gt;After rerunning the application, you’ll see a slider with the values for min, max, and step set ready for your users. Awesome!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This technique can work with any HTML5 input you’d like to support that isn’t in ASP.NET Core. It also ensures that all HTML &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; values derive from your C# models and that the HTML and server-side handlers are in sync.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and as always, thanks for reading. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/html-range-inputs-with-aspnet-core-taghelpers</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/html-range-inputs-with-aspnet-core-taghelpers</guid>
        
        <category>aspnet,</category>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>HTML5 Validation for ASP.NET Core Models and Razor Views</title>
        <description>&lt;p&gt;I was recently working on an HTMX and ASP.NET Core demo and wanted to limit client-to-server requests to valid requests. This is a built-in feature for HTMX, as long as you utilize HTML5 validators on your forms and inputs. As many ASP.NET Core practitioners know, the default client-side validation in ASP.NET Core is not HTML5 but a mix of custom &lt;code&gt;data-val&lt;/code&gt; attributes and JQuery. The current approach is acceptable, but it makes adopting new frameworks, supporting native HTML capabilities, and dropping extraneous dependencies more difficult.&lt;/p&gt;

&lt;p&gt;Could we drop the JQuery validation dependency in favor of HTML5 validation? Luckily, we can thank OSS author &lt;a href=&quot;https://www.finbuckle.com/&quot;&gt;Andrew White&lt;/a&gt; for his latest NuGet package, &lt;a href=&quot;https://github.com/Finbuckle/Finbuckle.Html5Validation&quot;&gt;FinBuckle.Html5Validation&lt;/a&gt;. This package allows us to disable the default behavior of ASP.NET Core MVC and Razor Pages for a more modern approach.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-html5-validation&quot;&gt;What is HTML5 Validation?&lt;/h2&gt;

&lt;p&gt;Before HTML5, developers wrote all client-side validation using JavaScript code. While JavaScript code allowed for complex scenarios, many folks realized two things: Client-side validation has many recurring patterns, and, ultimately, it’s not a bullet-proof validation approach. Server-side validation is essential.&lt;/p&gt;

&lt;p&gt;This realization helped HTML narrow down the scope of client-side validation, which limits requests sent to the server to client-validated ones. This validation focused on a few user input characteristics:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Required&lt;/strong&gt;: This field must have some value.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Type&lt;/strong&gt;: This field conforms to the expected integer, date, phone number, etc.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Constraints&lt;/strong&gt;: This field has a minimum, maximum, or fits within a specified range.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; This field conforms to a regular expression pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These agreed-upon validations reduced the required JavaScript code while allowing clients to create native experiences based on the input types.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example of an HTML5-validated form. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#full_example&quot;&gt;The following code can be seen on the MDN site.&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;form&amp;gt;
  &amp;lt;fieldset&amp;gt;
    &amp;lt;legend&amp;gt;
      Do you have a driver&apos;s license?&amp;lt;span aria-label=&quot;required&quot;&amp;gt;*&amp;lt;/span&amp;gt;
    &amp;lt;/legend&amp;gt;
    &amp;lt;input type=&quot;radio&quot; required name=&quot;driver&quot; id=&quot;r1&quot; value=&quot;yes&quot; /&amp;gt;&amp;lt;label
      for=&quot;r1&quot;
      &amp;gt;Yes&amp;lt;/label
    &amp;gt;
    &amp;lt;input type=&quot;radio&quot; required name=&quot;driver&quot; id=&quot;r2&quot; value=&quot;no&quot; /&amp;gt;&amp;lt;label
      for=&quot;r2&quot;
      &amp;gt;No&amp;lt;/label
    &amp;gt;
  &amp;lt;/fieldset&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;n1&quot;&amp;gt;How old are you?&amp;lt;/label&amp;gt;    
    &amp;lt;input
      type=&quot;number&quot;
      min=&quot;12&quot;
      max=&quot;120&quot;
      step=&quot;1&quot;
      id=&quot;n1&quot;
      name=&quot;age&quot;
      pattern=&quot;\d+&quot; /&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;t1&quot;
      &amp;gt;What&apos;s your favorite fruit?&amp;lt;span aria-label=&quot;required&quot;&amp;gt;*&amp;lt;/span&amp;gt;&amp;lt;/label
    &amp;gt;
    &amp;lt;input
      type=&quot;text&quot;
      id=&quot;t1&quot;
      name=&quot;fruit&quot;
      list=&quot;l1&quot;
      required
      pattern=&quot;[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range&quot; /&amp;gt;
    &amp;lt;datalist id=&quot;l1&quot;&amp;gt;
      &amp;lt;option&amp;gt;Banana&amp;lt;/option&amp;gt;
      &amp;lt;option&amp;gt;Cherry&amp;lt;/option&amp;gt;
      &amp;lt;option&amp;gt;Apple&amp;lt;/option&amp;gt;
      &amp;lt;option&amp;gt;Strawberry&amp;lt;/option&amp;gt;
      &amp;lt;option&amp;gt;Lemon&amp;lt;/option&amp;gt;
      &amp;lt;option&amp;gt;Orange&amp;lt;/option&amp;gt;
    &amp;lt;/datalist&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;t2&quot;&amp;gt;What&apos;s your email address?&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;email&quot; id=&quot;t2&quot; name=&quot;email&quot; /&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;label for=&quot;t3&quot;&amp;gt;Leave a short message&amp;lt;/label&amp;gt;
    &amp;lt;textarea id=&quot;t3&quot; name=&quot;msg&quot; maxlength=&quot;140&quot; rows=&quot;5&quot;&amp;gt;&amp;lt;/textarea&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;
  &amp;lt;/p&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you’ll notice, the attributes &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;pattern&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, and &lt;code&gt;type&lt;/code&gt; are all used to create a validation experience with no lines of JavaScript. When attempting to submit the form, you’ll notice the client displays a message. You can also highlight inputs based on their validation status.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/html5-validation-example.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/html5-validation-example.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/html5-validation-example.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/html5-validation-example.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_784/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/html5-validation-example.png 784w&quot; sizes=&quot;100vw&quot; alt=&quot;HTML5 validation on HTML Form&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;814&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Awesome, right?! With a bit of CSS, we can get some UI indicators. Depending on the client, any &lt;code&gt;input&lt;/code&gt; with an appropriate &lt;code&gt;type&lt;/code&gt; will have automatic access to the native type value picker, whether it’s a date, a phone number, or a number.&lt;/p&gt;

&lt;p&gt;OK, now that we understand what HTML5 validation gets us, how do we get that in ASP.NET Core?&lt;/p&gt;

&lt;h2 id=&quot;disable-client-side-validation-in-aspnet-core&quot;&gt;Disable Client-side Validation in ASP.NET Core&lt;/h2&gt;

&lt;p&gt;This section is for folks who’d prefer to keep their models and views completely separate and write the HTML mostly by hand.&lt;/p&gt;

&lt;p&gt;To disable the default client-side validation in ASP.NET Core MVC and Razor Pages, you can use the following lines in your &lt;code&gt;Program&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddRazorPages()
    .AddViewOptions(options =&amp;gt; {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will prevent Razor Pages and MVC from generating the &lt;code&gt;data-val&lt;/code&gt; attributes commonly found on inputs in the HTML output.&lt;/p&gt;

&lt;p&gt;This approach is fine, but I think the next section is a better option for most folks as it still relies on the model metadata that ASP.NET Core provides.&lt;/p&gt;

&lt;h2 id=&quot;finbucklehtml5validation-nuget-package&quot;&gt;FinBuckle.HTML5Validation NuGet Package&lt;/h2&gt;

&lt;p&gt;To move towards HTML5 validation, you must first install the &lt;code&gt;FinBuckle.HTML5Validation&lt;/code&gt; NuGet package into your ASP.NET Core application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Note: this package only works with MVC and Razor Pages.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PackageReference Include=&quot;Finbuckle.Html5Validation&quot; Version=&quot;1.0.1&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once added to your dependencies, you must register the package with your application’s services collection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Finbuckle.Html5Validation;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHtml5Validation();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Internally, this method provides the ASP.NET Core pipeline with an &lt;code&gt;IValidationAttributeAdapterProvider&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace Microsoft.AspNetCore.Mvc.DataAnnotations
{
  public interface IValidationAttributeAdapterProvider
  {
    IAttributeAdapter? GetAttributeAdapter(
      ValidationAttribute attribute,
      IStringLocalizer? stringLocalizer);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This adapter gets passed an attribute and a localizer, at which point you can decide what attributes should be added to the HTML input. Let’s see an implementation for the &lt;code&gt;pattern&lt;/code&gt; attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// Copyright Finbuckle LLC, Andrew White, and Contributors.
// Refer to the solution LICENSE file for more information.

// Portions of this file are derived from ASP.NET Core and are subject to the following:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;

namespace Finbuckle.Html5Validation.Internal;

public class RegularExpressionAttributeAdapter : AttributeAdapterBase&amp;lt;RegularExpressionAttribute&amp;gt;
{
    public RegularExpressionAttributeAdapter(RegularExpressionAttribute attribute, IStringLocalizer? stringLocalizer)
        : base(attribute, stringLocalizer)
    {
    }

    public override void AddValidation(ClientModelValidationContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }
        
        MergeAttribute(context.Attributes, &quot;pattern&quot;, Attribute.Pattern);
    }

    /// &amp;lt;inheritdoc /&amp;gt;
    public override string GetErrorMessage(ModelValidationContextBase validationContext)
    {
        if (validationContext == null)
        {
            throw new ArgumentNullException(nameof(validationContext));
        }

        return GetErrorMessage(
            validationContext.ModelMetadata,
            validationContext.ModelMetadata.GetDisplayName(),
            Attribute.Pattern);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a neat part of the ASP.NET Core MVC and Razor Pages pipeline. It’s extensible to the point where folks can replace validation without changing Razor views. Speaking of Razor views, let’s see how we can use this in one.&lt;/p&gt;

&lt;p&gt;First, let’s create a Razor PageModel.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace HtmxFormValidation.Pages;

public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    [BindProperty, Required]
    public string? Name { get; set; }
    
    [BindProperty, Required]
    public string? Media { get; set; }
    
    [BindProperty, Required]
    public DateTime? Date { get; set; }
    
    public void OnGet()
    {
    }

    public IActionResult OnPost()
    {
        if (ModelState.IsValid)
        {
            logger.LogInformation(&quot;{Name} picked {Media}&quot;, Name, Media);
        }

        return Partial(&quot;_Form&quot;, this);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m using DataAnnotations here; now, what does the view look like? (I’m using HTMX, hence the &lt;code&gt;hx-&lt;/code&gt; attributes).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@model IndexModel
@{ string[] options = [&quot;Television&quot;, &quot;Radio&quot;, &quot;Social Media&quot;]; }

&amp;lt;form method=&quot;post&quot; asp-page=&quot;Index&quot;
      hx-post=&quot;@Url.Page(&quot;Index&quot;)&quot;
      hx-swap=&quot;outerHtml&quot;&amp;gt;

    @* alert box *@
    @if (Model.Name is not null)
    {
        &amp;lt;div class=&quot;alert alert-info mb-3&quot;&amp;gt;
            @Model.Name picked @Model.Media!
        &amp;lt;/div&amp;gt;
    }

    &amp;lt;div class=&quot;form-group mb-2&quot;&amp;gt;
        &amp;lt;label asp-for=&quot;Name&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;input asp-for=&quot;Name&quot; type=&quot;text&quot;
               class=&quot;form-control&quot; 
               title=&quot;Must be Khalid or RoboCop&quot;&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class=&quot;form-group mb-2&quot;&amp;gt;
        &amp;lt;label asp-for=&quot;Date&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;input asp-for=&quot;Date&quot; class=&quot;form-control&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    
    &amp;lt;!-- radio button list --&amp;gt;
    &amp;lt;div class=&quot;mb-3&quot;&amp;gt;
        &amp;lt;label&amp;gt;Media Types&amp;lt;/label&amp;gt;
        @foreach (var option in options)
        {
            &amp;lt;div class=&quot;form-check&quot;&amp;gt;
                &amp;lt;input class=&quot;form-check-input&quot; type=&quot;radio&quot; asp-for=&quot;Media&quot; value=&quot;@option&quot;&amp;gt;
                &amp;lt;label class=&quot;form-check-label&quot; asp-for=&quot;Media&quot;&amp;gt;
                    @option
                &amp;lt;/label&amp;gt;
            &amp;lt;/div&amp;gt;
        }
    &amp;lt;/div&amp;gt;
    &amp;lt;button type=&quot;submit&quot; class=&quot;btn btn-primary &quot;&amp;gt;
        Submit
    &amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! Now we need some CSS to highlight invalid fields with some styling.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;input:user-invalid {
  border-color: red;
  background-color: pink;
  box-shadow: 0 0 5px 1px red;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can target several states, such as &lt;code&gt;:valid&lt;/code&gt;, &lt;code&gt;:invalid&lt;/code&gt;, and &lt;code&gt;:user-invalid&lt;/code&gt;. The &lt;code&gt;:user-invalid&lt;/code&gt; state only triggers after a user has interacted with an element, whereas you can use the &lt;code&gt;:invalid&lt;/code&gt; state to signify a field is invalid immediately.&lt;/p&gt;

&lt;p&gt;Let’s run our application and submit the form.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1042/https://khalidabuhakmeh.com/assets/images/posts/aspnetcore-html5-validation/aspnetcore-html5-validation.png 1042w&quot; sizes=&quot;100vw&quot; alt=&quot;ASP.NET Core HTML form with HTML5 validation&quot; loading=&quot;lazy&quot; width=&quot;1042&quot; height=&quot;748&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sweet! All looks like it’s working as expected.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While validation libraries can offer a lot in terms of user experience, the native validation is really good. In fact, it’s good enough to handle most client-side validation and then additionally lean on server-side validation to handle the rest.&lt;/p&gt;

&lt;p&gt;I recommend trying this approach and seeing how far you get. You’ll likely be surprised how many dependencies you can drop in favor of native controls and validation.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 25 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/html5-validation-for-aspnet-core-models-and-razor-views</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/html5-validation-for-aspnet-core-models-and-razor-views</guid>
        
        <category>aspnet,</category>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>What is HSTS and why is it in my ASP.NET Core app?</title>
        <description>&lt;p&gt;When creating a new ASP.NET Core application, you get a set of middleware that performs typical web application duties. Some include serving static assets, routing, HTTPS redirection, and exception handling. Folks looking will also notice a middleware registration of the &lt;code&gt;app.UseHsts()&lt;/code&gt; found in every ASP.NET Core app.&lt;/p&gt;

&lt;p&gt;What is HSTS, why would you want it, and how do you configure the HSTS options in ASP.NET Core? Let’s find out.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-hsts&quot;&gt;What is HSTS?&lt;/h2&gt;

&lt;p&gt;HSTS (HTTP Strict Transport Security) is a method by which your application server can tell clients to use a secure connection when sending requests. As you may know, HTTP is unsecured communication, while HTTPS uses encryption to improve users’ privacy and security. Applications can transition user sessions from HTTP and HTTPS, and historically, it was very common to move from an unsecured part of a website to a secured section. For example, shopping sites used to display store items over HTTP and then only use HTTPS for the checkout process.&lt;/p&gt;

&lt;p&gt;This still happens in ASP.NET Core today, but typically only on the first request to the application. You may notice this line somewhere in your ASP.NET Core pipeline definition.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.UseHttpsRedirection();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If a user visits your application using &lt;code&gt;http://&lt;/code&gt;, the ASP.NET Core middleware will attempt to rewrite the request to target &lt;code&gt;https://&lt;/code&gt;. This is all good and secure, well, except for that first request, and that’s the crucial part. There’s still some unsecured communication occurring, which can be an issue depending on what is included in that initial request.&lt;/p&gt;

&lt;p&gt;With HSTS, we want to communicate several aspects to any client accessing our application:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Always communicate using HTTPS, no matter what.&lt;/li&gt;
  &lt;li&gt;If &lt;code&gt;includeSubdomains&lt;/code&gt; is present we also mean all subdomains.&lt;/li&gt;
  &lt;li&gt;If &lt;code&gt;preload&lt;/code&gt; is set, the browser will always make HTTPS requests, even on the first request.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;max-age&lt;/code&gt; of the policy, which can be measured in seconds to years.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;preload&lt;/code&gt; value is the most interesting, as this is used by browser vendors to create a known list of sites serving only experiences over HTTPS. This allows the browser to switch to HTTPS before the first request. A browser will never communicate with your application over HTTP, even if your server supports it.&lt;/p&gt;

&lt;p&gt;While you may be tempted to turn on HSTS and the &lt;code&gt;preload&lt;/code&gt; functionality immediately, you must be mindful of what’s expected of your application before deploying this feature.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Serve and maintain a valid certificate&lt;/li&gt;
  &lt;li&gt;Redirect from HTTP to HTTPS on the same host&lt;/li&gt;
  &lt;li&gt;Serve all subdomains over HTTPS&lt;/li&gt;
  &lt;li&gt;Serve an HSTS header with a &lt;code&gt;max-age&lt;/code&gt; of 1 year, &lt;code&gt;includeSubdomains&lt;/code&gt;, and include the &lt;code&gt;preload&lt;/code&gt; key.&lt;/li&gt;
  &lt;li&gt;Redirect responses must also contain the HSTS header.&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;code&gt;`Strict-Transport-Security:` `max-age=63072000; includeSubDomains; preload`
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally, you can verify that you’ve satisfied all the requirements by going to https://hstspreload.org.&lt;/p&gt;

&lt;p&gt;In summary, HSTS allows you to tell browser vendors that you want an added level of security by having all communication occur over encrypted communication and that requests or responses should never be unsecured. In short, enforce HTTPS.&lt;/p&gt;

&lt;h2 id=&quot;hsts-in-aspnet-core&quot;&gt;HSTS in ASP.NET Core&lt;/h2&gt;

&lt;p&gt;Let’s get back to ASP.NET Core. You’ve likely seen this line in your applications but never clicked through the link in the comment.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why is the default value 30 days, and why should you consider changing it for production scenarios?&lt;/p&gt;

&lt;p&gt;30 days is a nice round number, just long enough to be helpful but not so long that if you make a mistake, it will take forever for browser vendors to resolve. That said, you should change the value for production. The HSTS preload guidance is a gradual smoke test and will likely take a few application deployments to work through.&lt;/p&gt;

&lt;p&gt;Start with a low &lt;code&gt;max-age&lt;/code&gt; of 5 minutes, test your site, then graduate to 1 week and to 1 month.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;max-age=2592000; includeSubDomains
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Along the way, test your site for errors or issues related to HTTPS traffic. Standard HTTP to HTTPS issues include static assets and CDN dependencies. When you feel confident you’ve squashed all your issues, you can add the &lt;code&gt;preload&lt;/code&gt; value and increase the &lt;code&gt;max-age&lt;/code&gt; to 2 years.&lt;/p&gt;

&lt;p&gt;You’ll need to configure the &lt;code&gt;HstsOptions&lt;/code&gt; object registered in your ASP.NET Core services collection to work up to this.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.Configure&amp;lt;HstsOptions&amp;gt;(o =&amp;gt;
{
    o.Preload = true;
    o.MaxAge = new TimeSpan(730 /* 2 years */);
    o.IncludeSubDomains = true;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The next time your site is crawled by the major browser providers (Google, Mozilla, or Microsoft), you’ll be added to the preload list hard-coded into browsers.&lt;/p&gt;

&lt;p&gt;If you’re running a multi-tenant site and need to exclude different tenants from a particular policy, you can also set the &lt;code&gt;ExcludeHosts&lt;/code&gt; property.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.Configure&amp;lt;HstsOptions&amp;gt;(o =&amp;gt;
{
    o.Preload = true;
    o.MaxAge = new TimeSpan(730 /* 2 years */);
    o.IncludeSubDomains = true;
    o.ExcludedHosts.Add(&quot;example.com&quot;);
    o.ExcludedHosts.Add(&quot;www.example.com&quot;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Just note that if you exclude a subdomain from a top-level domain that opts into HSTS, you can’t get the preload capability since you’ve not satisfied the requirements.&lt;/p&gt;

&lt;h2 id=&quot;should-i-turn-on-hsts&quot;&gt;Should I turn on HSTS?&lt;/h2&gt;

&lt;p&gt;HSTS is an added layer of security that can prevent man-in-the-middle attacks from protocol downgrades and cookie hijacking. That said, ASP.NET Core has mechanisms to secure cookies, such as Data Protection encryption and browser-handling hints such as &lt;code&gt;Secure&lt;/code&gt;, &lt;code&gt;HttpOnly&lt;/code&gt;, and &lt;code&gt;SameSite&lt;/code&gt;. As long as you don’t change those values, you’ll be following best practices. That said, always consult an actual security professional and perform security audits periodically.&lt;/p&gt;

&lt;p&gt;HSTS can be annoying if you accidentally enable it in a development environment that may not have a certificate, but in most production environments, you should have a certificate.&lt;/p&gt;

&lt;p&gt;In general, yes, you should enable it, but be mindful when and where you enable it, as it can be challenging to get browsers to refresh the policy.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;You now know a little bit more about HSTS, why it’s included in your ASP.NET Core application, and how and when to configure it. HSTS is an additional layer of security specifically designed to keep all communication over HTTPS, including those initial requests. That said, you’ll need to put in the work to get that &lt;code&gt;preload&lt;/code&gt; functionality and plan for weeks of deployments, testing, and audits to make sure everything is working smoothly.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading, and cheers.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/security/2012/11/01/preloading-hsts/&quot;&gt;Mozilla - Preloading HSTS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hstspreload.org/&quot;&gt;HSTS Preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-8.0&amp;amp;viewFallbackFrom=aspnetcore-2.1&amp;amp;tabs=visual-studio,linux-ubuntu#http-strict-transport-security-protocol-hsts&quot;&gt;Enforce HTTPS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-8.0&quot;&gt;SameSite cookies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 18 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/what-is-hsts-and-why-is-it-in-my-aspnet-core-app</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/what-is-hsts-and-why-is-it-in-my-aspnet-core-app</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How To Encrypt ASP.NET Core Route Parameters</title>
        <description>&lt;p&gt;I recently read &lt;a href=&quot;https://ravendb.net/articles/avoiding-exposing-identifier-details-to-your-users&quot;&gt;a classic blog post from the RavenDB community&lt;/a&gt; recommending developers think twice about exposing primary identifiers in their URLs. There are several reasons for this, which I’ll summarize in this post, but I wanted to revisit the problem and see what the current ASP.NET Core development stack has to offer when it comes to solving this problem.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see some code that can both encrypt and decrypt &lt;em&gt;sensitive&lt;/em&gt; identifiers in the URL path.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-obscure-identifiers&quot;&gt;Why Obscure Identifiers?&lt;/h2&gt;

&lt;p&gt;Many people first think, “Why obscure identifiers in the first place?” I mean, it’s just an ID, right?&lt;/p&gt;

&lt;p&gt;There are several arguments as to why it may be a “bad” practice.&lt;/p&gt;

&lt;h3 id=&quot;1-url-tampering&quot;&gt;1. URL Tampering&lt;/h3&gt;

&lt;p&gt;While we all do our best to secure our applications, there are times when we may forget to properly verify that a user has permission to access a particular resource.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://example.com/?id=1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Over the years, we’ve become acutely aware that changing the value of the &lt;code&gt;id&lt;/code&gt; in a URL might return a different resource. This may be intended behavior, or it could give “hackers” another avenue to exfiltrate data from your system.&lt;/p&gt;

&lt;p&gt;Making identifiers more opaque can eliminate a user experience you never intended to offer.&lt;/p&gt;

&lt;h3 id=&quot;2-leaking-system-information&quot;&gt;2. Leaking System Information&lt;/h3&gt;

&lt;p&gt;Most identifiers can be tied back to their supporting system. For example, integers are widely used in relational databases, while document databases use string identifiers. This extra information may give users more information about your internal system and architectural choices than you intended.&lt;/p&gt;

&lt;h3 id=&quot;3-leaking-business-information&quot;&gt;3. Leaking Business Information&lt;/h3&gt;

&lt;p&gt;This is likely the most important for your business stakeholders. Since most identifiers are incremental, they could accidentally leak your business’s critical metrics to outside parties. You could track the current volume and growth velocity over time of a system type. Some hypothetical entities may include orders, issues, and products.&lt;/p&gt;

&lt;p&gt;The reasons given here clearly rely on your context and your application security. So, while you may or may not ultimately decide to obscure identifiers, it’s still important to consider why you’re making that decision.&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-route-constraints&quot;&gt;ASP.NET Core Route Constraints&lt;/h2&gt;

&lt;p&gt;In this code, we’ll use ASP.NET Core’s route constraints to provide an implicit way of encrypting identifiers in route templates. We’ll also use the &lt;code&gt;DataProtection&lt;/code&gt; APIs, so we don’t have to worry about encryption keys and storage for this example. However, you could adapt this code to use any methodology you have in mind.&lt;/p&gt;

&lt;p&gt;The first step is to create a new class called &lt;code&gt;EncryptedParameter&lt;/code&gt;, and we’ll need to implement the &lt;code&gt;IOutboundParameterTransformer&lt;/code&gt; interface.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.DataProtection;

public class EncryptedParameter(IDataProtectionProvider dpp) : 
    IOutboundParameterTransformer
{
    private readonly IDataProtector protector 
        = dpp.CreateProtector(&quot;EncryptedParameter&quot;);
    
    public string? TransformOutbound(object? value)
    {
        var result = value?.ToString();
        return string.IsNullOrEmpty(result) 
            ? null 
            : protector.Protect(result);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We need to register this code as a route constraint. Add the following code to the &lt;code&gt;Program&lt;/code&gt; class of your ASP.NET Core application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddDataProtection();
builder.Services.Configure&amp;lt;RouteOptions&amp;gt;(opt =&amp;gt;  {
    opt.ConstraintMap.Add(&quot;encrypt&quot;, typeof(EncryptedParameter));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We have to register the constraint, and since our constraint is using the &lt;code&gt;DataProtection&lt;/code&gt; API, we also need to remember to add the data protection services.&lt;/p&gt;

&lt;p&gt;We can now use the constraint in our route templates on our target actions. Here’s an example being used in a Razor Page route template.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;{id:encrypt}&quot;
@model RavenDbTodoApp.Pages.Agenda

&amp;lt;h1&amp;gt;@Model.Id&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we use ASP.NET Core’s &lt;code&gt;LinkGenerator&lt;/code&gt;, it will use our constraint to process parameters.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;a href=&quot;@Url.Page(&quot;Agenda&quot;, new { id = &quot;agenda/1&quot; })&quot;&amp;gt;
    Link To Agenda
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The previous code generates the following HTML link.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a href=&quot;/Agenda/CfDJ8LTlmMRHw3JNmUOvTfhPRjsGI3dXCSP-7yuu-Hu05yjURdIZkalKYJc7-rbJbOXrJCkeLdywxW7m6A7XT3ylMY6ilrNC5DYdssyWTA1-QCHpqFFvRi6LokwktvGkcGs5BA&quot;&amp;gt;
    Link To Agenda
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat, but as you may have noticed, this is only one part of the equation. Dealing with these identifiers may become cumbersome if we don’t use the ASP.NET Core machinery. Let’s implement the second part.&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-model-binders&quot;&gt;ASP.NET Core Model Binders&lt;/h2&gt;

&lt;p&gt;We’ll be using ASP.NET Core’s model binding machinery to transform the incoming parameter into something more usable. Let’s modify our &lt;code&gt;EncryptedParameter&lt;/code&gt; class with a new interface, &lt;code&gt;IModelBinder&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc.ModelBinding;

public class EncryptedParameter(IDataProtectionProvider dpp) : 
    IModelBinder,
    IOutboundParameterTransformer
{
    private readonly IDataProtector protector 
        = dpp.CreateProtector(&quot;EncryptedParameter&quot;);
    
    public string? TransformOutbound(object? value)
    {
        var result = value?.ToString();
        return string.IsNullOrEmpty(result) 
            ? null 
            : protector.Protect(result);
    }

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var key = bindingContext.FieldName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
        
        if (valueProviderResult.FirstValue is { } value)
        {
            var result = protector.Unprotect(value);
            bindingContext.Result = ModelBindingResult.Success(result);
        }

        return Task.CompletedTask;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s apply this model binder to a parameter on the receiving page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

public class Agenda: PageModel
{
    [BindProperty(SupportsGet = true, BinderType = typeof(EncryptedParameter))]
    public string Id { get; set; }
    
    public void OnGet()
    {
        
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, you can access the parameter with its original value, which should make it easier to use against your existing data storage engine of choice.&lt;/p&gt;

&lt;h2 id=&quot;some-thoughts-on-this-approach&quot;&gt;Some thoughts on this approach&lt;/h2&gt;

&lt;p&gt;You may want to evaluate a few things when taking this approach and whether it’s worth the tradeoffs.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Encryption and Decryption can be expensive, adding to the overhead of each link generation and request.&lt;/li&gt;
  &lt;li&gt;Encryption creates some really long strings. I’m not an encryption expert, but there are likely encryption algorithms that produce more compact strings.&lt;/li&gt;
  &lt;li&gt;A little more noise in code with constraints and attributes.&lt;/li&gt;
  &lt;li&gt;Easy to miss a constraint or attribute as the system grows.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you’ve been worried about URL tampering or exposing critical system information, the approach outlined in this post might be useful to you. That said, before slapping this onto your applications, please consider the trade-offs and costs of applying encryption to parameters.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and I hope this article has helped. Cheers&lt;/p&gt;
</description>
        <pubDate>Tue, 11 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-encrypt-aspnet-core-route-parameters</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-encrypt-aspnet-core-route-parameters</guid>
        
        <category>aspnet,</category>
        
        <category>security</category>
        
        
      </item>
    
      <item>
        <title>State Machines, Light Switches, and Space Travel with Stateless and .NET 8</title>
        <description>&lt;p&gt;State machines are so integral to software development that they often seem invisible to developers. They are used so
frequently yet abstracted away through APIs and syntax that many developers don’t directly deal with them. However, we’d
like to.&lt;/p&gt;

&lt;p&gt;At their core, state machines are systems with finite inputs and deterministic pathways. While they can be complex, the
basic structure of nodes and vertices makes them more approachable than they may initially seem.&lt;/p&gt;

&lt;p&gt;In this post, I’ll guide you through the process of building two state machines using the .NET
library &lt;a href=&quot;https://github.com/dotnet-state-machine/stateless&quot;&gt;Stateless&lt;/a&gt;. We’ll
also discuss effective strategies for incorporating state machines into your code.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;getting-started-with-stateless&quot;&gt;Getting Started with Stateless&lt;/h2&gt;

&lt;p&gt;To start using &lt;a href=&quot;https://github.com/dotnet-state-machine/stateless&quot;&gt;Stateless&lt;/a&gt;, you’ll need to install the latest version
of the package using NuGet.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotnet add package Stateless
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here, you will use the StateMachine class to define the state object and the triggers that mutate the machine’s
state.&lt;/p&gt;

&lt;p&gt;The example used in the Stateless documentation is that of a phone.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var phoneCall = new StateMachine&amp;lt;State, Trigger&amp;gt;(State.OffHook);

phoneCall.Configure(State.OffHook)
    .Permit(Trigger.CallDialled, State.Ringing);

phoneCall.Configure(State.Connected)
    .OnEntry(t =&amp;gt; StartCallTimer())
    .OnExit(t =&amp;gt; StopCallTimer())
    .InternalTransition(Trigger.MuteMicrophone, t =&amp;gt; OnMute())
    .InternalTransition(Trigger.UnmuteMicrophone, t =&amp;gt; OnUnmute())
    .InternalTransition&amp;lt;int&amp;gt;(_setVolumeTrigger, (volume, t) =&amp;gt; OnSetVolume(volume))
    .Permit(Trigger.LeftMessage, State.OffHook)
    .Permit(Trigger.PlacedOnHold, State.OnHold);

// ...

phoneCall.Fire(Trigger.CallDialled);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice that the &lt;code&gt;StateMachine&lt;/code&gt; has two generic arguments: one for the state and the other for the trigger. These
types can be any .NET type, but they’re &lt;code&gt;enum&lt;/code&gt; types in this sample.&lt;/p&gt;

&lt;p&gt;Let’s build something closer to how I recommend using Stateless.&lt;/p&gt;

&lt;h2 id=&quot;the-light-switch-state-machine-example&quot;&gt;The Light Switch State Machine Example&lt;/h2&gt;

&lt;p&gt;This example shows a &lt;code&gt;Widget&lt;/code&gt; class that always has a deterministic state of being &lt;code&gt;On&lt;/code&gt; or &lt;code&gt;Off&lt;/code&gt;. The trigger for
our &lt;code&gt;Widget&lt;/code&gt; is to &lt;code&gt;Press&lt;/code&gt;. While we could implement the state machine as we did previously, I recommend encapsulating
state machines within a class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Widget
{
    private readonly StateMachine&amp;lt;State, Trigger&amp;gt; workflow = new(State.Off);
    public string Name { get; }

    enum State
    {
        On,
        Off
    }
    enum Trigger
    {
        Press
    }

    public Widget(string name)
    {
        Name = name;
        
        workflow.Configure(State.On)
            .Permit(Trigger.Press, State.Off)
            .OnEntry(() =&amp;gt; Console.WriteLine($&quot;🟢 {Name} is {workflow.State}&quot;));
        
        workflow.Configure(State.Off)
            .Permit(Trigger.Press, State.On)
            .OnEntry(() =&amp;gt; Console.WriteLine($&quot;🔴 {Name} is {workflow.State}&quot;));
    }

    public void Toggle()
    {
        workflow.Fire(Trigger.Press);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why? It’s much easier to consume these class instances and have the machine’s state exposed through properties and
interactions to exist as a method call. In the “real world,” we typically don’t understand the internal behavior of the
abstractions we interact with; we only observe the outcome of our interactions.&lt;/p&gt;

&lt;p&gt;In the case of this implementation, Stateless is managing the state of our &lt;code&gt;Widget&lt;/code&gt;, and we know it will be consistent
with the behavior we define in the constructor.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var widget = new Widget(&quot;Lightbulb 💡&quot;);

Console.WriteLine($&quot;Press any key to toggle {widget.Name}&quot;);
while (true) {
    _ = Console.ReadKey();
    widget.Toggle();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see it in action!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Press any key to toggle Lightbulb 💡
🟢 Lightbulb 💡 is On
🔴 Lightbulb 💡 is Off
🟢 Lightbulb 💡 is On
🔴 Lightbulb 💡 is Off
🟢 Lightbulb 💡 is On
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a neat technique, but admittedly simple. Let’s go to space next.&lt;/p&gt;

&lt;h2 id=&quot;space-travel-with-state-machines&quot;&gt;Space Travel with State Machines&lt;/h2&gt;

&lt;p&gt;A challenging concept when working with state machines is managing the state. Luckily, with Stateless, extracting,
storing, and rehydrating state is straightforward.&lt;/p&gt;

&lt;p&gt;Let’s create a state machine to travel through our solar system.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class SpaceTravel
{
    public record Planet(String Name, int DistanceFromSunInMillionsOfMiles)
    {
        public static readonly Planet Sun = new(nameof(Sun), 0);
        public static readonly Planet Mercury = new(nameof(Mercury), 36);
        public static readonly Planet Venus = new(nameof(Venus), 67);
        public static readonly Planet Earth = new(nameof(Earth), 93);
        public static readonly Planet Mars = new(nameof(Mars), 142);
        public static readonly Planet Jupiter = new(nameof(Jupiter), 484);
        public static readonly Planet Saturn = new(nameof(Saturn), 886);
        public static readonly Planet Uranus = new(nameof(Uranus), 1784);
        public static readonly Planet Neptune = new(nameof(Neptune), 2793);
        public static readonly Planet Pluto = new(nameof(Pluto), 3670);
        
        public static readonly List&amp;lt;Planet&amp;gt; All = [
            Sun, Mercury, Venus,
            Earth, Mars, Jupiter,
            Saturn, Uranus, Neptune,
            Pluto
        ];

        public override string ToString()
        {
            return $&quot;{Name}&quot;;
        }
    }

    enum Actions
    {
        In,
        Out
    }

    private readonly StateMachine&amp;lt;Planet, Actions&amp;gt; machine;
    
    public SpaceTravel(Planet? start = null)
    {
        start ??= Planet.Earth;

        if (!Planet.All.Contains(start))
        {
            throw new Exception(&quot;Starting planet must be in our solar system&quot;);
        }

        machine = new(start);
        
        machine.OnTransitionCompleted((transition =&amp;gt;
        {
            var (source, destination, direction) = transition;
            var distance = Math.Abs(source.DistanceFromSunInMillionsOfMiles - destination.DistanceFromSunInMillionsOfMiles);
            var dir = direction == Actions.In ? &quot;⬇&quot; : &quot;⬆&quot;;
            Console.WriteLine($&quot;{dir} 🚀 You traveled {distance} million miles from {source.Name} to {destination.Name}.&quot;);
        }));
        
        machine.Configure(Planet.Sun).Ignore(Actions.In).Permit(Actions.Out, Planet.Mercury);
        machine.Configure(Planet.Mercury).Permit(Actions.In, Planet.Sun).Permit(Actions.Out, Planet.Venus);
        machine.Configure(Planet.Venus).Permit(Actions.In, Planet.Mercury).Permit(Actions.Out, Planet.Earth);
        machine.Configure(Planet.Earth).Permit(Actions.In, Planet.Venus).Permit(Actions.Out, Planet.Mars);
        machine.Configure(Planet.Mars).Permit(Actions.In, Planet.Earth).Permit(Actions.Out, Planet.Jupiter);
        machine.Configure(Planet.Jupiter).Permit(Actions.In, Planet.Mars).Permit(Actions.Out, Planet.Saturn);
        machine.Configure(Planet.Saturn).Permit(Actions.In, Planet.Jupiter).Permit(Actions.Out, Planet.Uranus);
        machine.Configure(Planet.Uranus).Permit(Actions.In, Planet.Saturn).Permit(Actions.Out, Planet.Neptune);
        machine.Configure(Planet.Neptune).Permit(Actions.In, Planet.Uranus).Permit(Actions.Out, Planet.Pluto);
        machine.Configure(Planet.Pluto).Ignore(Actions.Out).Permit(Actions.In, Planet.Neptune);
    }

    public Planet Current =&amp;gt; machine.State;

    public void In()
    {
        machine.Fire(Actions.In);
    }

    public void Out()
    {
        machine.Fire(Actions.Out);
    }
}

internal static class StateMachineExtensions {
    public static void Deconstruct&amp;lt;TState, TTrigger&amp;gt;(this StateMachine&amp;lt;TState, TTrigger&amp;gt;.Transition transition,
        out TState source, out TState destination, out TTrigger direction)
    {
        source = transition.Source;
        destination = transition.Destination;
        direction = transition.Trigger;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ve done a few things with this state machine that are more complex than our &lt;code&gt;Widget&lt;/code&gt; example.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The initial state of our &lt;code&gt;StateMachine&lt;/code&gt; can be set at instantiation time through the constructor.&lt;/li&gt;
  &lt;li&gt;There are two triggers of &lt;code&gt;In&lt;/code&gt; and &lt;code&gt;Out&lt;/code&gt;, both of which can be fired through matching methods.&lt;/li&gt;
  &lt;li&gt;The constructor defines how travel can occur from one planet to another, with the &lt;code&gt;Sun&lt;/code&gt; and &lt;code&gt;Pluto&lt;/code&gt; being re-entry
nodes. (You can’t leave the solar system).&lt;/li&gt;
  &lt;li&gt;Each transition calculates the distance between two bodies, regardless of the state change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s do some space travel!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var system = new SpaceTravel(SpaceTravel.Planet.Earth);
Console.WriteLine(&quot;🔭 Use O(ut) or ⬆ and I(n) and ⬇ keys to move through our solar system.&quot;);

while (true)
{
    var key = Console.ReadKey(true);
    switch (key)
    {
        case { Key: ConsoleKey.O or ConsoleKey.UpArrow }:
            system.Out();
            break;
        case { Key: ConsoleKey.I or ConsoleKey.DownArrow }:
            system.In();
            break;
        default:
            var miles = system.Current.DistanceFromSunInMillionsOfMiles;
            Console.WriteLine($&quot;🛰️ Currently at {system.Current.Name} ({miles} million miles from the ☀️).&quot;);
            break;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running the application, we get the sample output.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;🔭 Use O(ut) or ⬆ and I(n) and ⬇ keys to move through our solar system.
⬆ 🚀 You traveled 49 million miles from Earth to Mars.
⬆ 🚀 You traveled 342 million miles from Mars to Jupiter.
⬆ 🚀 You traveled 402 million miles from Jupiter to Saturn.
⬆ 🚀 You traveled 898 million miles from Saturn to Uranus.
⬆ 🚀 You traveled 1009 million miles from Uranus to Neptune.
⬆ 🚀 You traveled 877 million miles from Neptune to Pluto.
🛰️ Currently at Pluto (3670 million miles from the ☀️).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat! What about seeing our travel path?&lt;/p&gt;

&lt;h2 id=&quot;graphing-your-state-machines&quot;&gt;Graphing your State Machines&lt;/h2&gt;

&lt;p&gt;At any point in time, you can use the &lt;code&gt;UmlDotGraph&lt;/code&gt; static class in the Stateless library to output the graph to a
string value.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var graph = UmlDotGraph.Format(workflow.GetInfo());
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our light switch sample produces the following &lt;strong&gt;DotGraph&lt;/strong&gt; that can be turned into an SVG.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;digraph {
compound=true;
node [shape=Mrecord]
rankdir=&quot;LR&quot;
&quot;On&quot; [label=&quot;On|entry / Function&quot;];
&quot;Off&quot; [label=&quot;Off|entry / Function&quot;];

&quot;On&quot; -&amp;gt; &quot;Off&quot; [style=&quot;solid&quot;, label=&quot;Press&quot;];
&quot;Off&quot; -&amp;gt; &quot;On&quot; [style=&quot;solid&quot;, label=&quot;Press&quot;];
 init [label=&quot;&quot;, shape=point];
 init -&amp;gt; &quot;Off&quot;[style = &quot;solid&quot;]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These visualizations can be helpful for documentation or diagnosing issues when exceptions occur in the state machine.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Stateless is a very cool library worth checking out. It can add the necessary structure to otherwise complex workflows.
I highly recommend encapsulating the &lt;code&gt;StateMachine&lt;/code&gt; class within a container class; otherwise, you’ll be dealing with
some unwieldy APIs.&lt;/p&gt;

&lt;p&gt;A slew of APIs not covered in this post can help you determine if an action can be executed, what next steps are
permitted, and error handling for unhandled triggers. It is a well-thought-out library, and I hope you try it.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 04 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/state-machines-light-switches-and-space-travel-with-stateless-and-dotnet-8</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/state-machines-light-switches-and-space-travel-with-stateless-and-dotnet-8</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Blazor HTML Forms, Submitting, and Antiforgery Tokens</title>
        <description>&lt;p&gt;I love the web and HTML. It’s certainly come a long way since its inception and what it provides as a core experience
for web developers. While folks can certainly build HTML-exclusive experiences, adding forms on a page inevitably leads
to introducing a backend tech stack. Recently, I’ve been experimenting with Blazor Server-side Rendering (SSR) and how
developers can use its component-driven approach while still building the web experience they know and love.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to use the plain-old &lt;code&gt;form&lt;/code&gt; tag with a Blazor SSR page, handle form posts, and attach
antiforgery tokens.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-not-use-editform&quot;&gt;Why not use EditForm?&lt;/h2&gt;

&lt;p&gt;Anyone familiar with Blazor would likely immediately think, “Why not use
the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.forms.editform?view=aspnetcore-8.0&quot;&gt;&lt;code&gt;EditForm&lt;/code&gt;&lt;/a&gt;
component?” Well, for my taste, the &lt;code&gt;EditForm&lt;/code&gt; component has so many hooks, fields, and requirements that it begins to
feel like a burden compared to the humble HTML form. In my opinion, much of the &lt;code&gt;EditForm&lt;/code&gt; functionality is overkill for
an SSR scenario.&lt;/p&gt;

&lt;p&gt;You’re welcome to use &lt;code&gt;EditForm&lt;/code&gt; if you find its features useful.&lt;/p&gt;

&lt;h2 id=&quot;html-form-blazor-basics&quot;&gt;HTML Form Blazor Basics&lt;/h2&gt;

&lt;p&gt;Blazor is a component-driven framework, and even top-level pages are considered components. In a way, it’s simpler to
think of each component as a tree of other components, and you have to start somewhere. This approach means that a
component page must handle all incoming requests and “route” those requests to the appropriate handlers.&lt;/p&gt;

&lt;p&gt;In a Blazor application, there are two levels of “routing”. The first is what you’d consider traditional HTTP path
routing using the &lt;code&gt;@page&lt;/code&gt; directive. The second uses the &lt;code&gt;@formname&lt;/code&gt; attribute on a &lt;code&gt;form&lt;/code&gt; to inject a handler name into
forms, in which you can use that additional information for application logic.&lt;/p&gt;

&lt;p&gt;Let’s add a basic form to a page and submit it to a Blazor component. &lt;strong&gt;THIS WILL NOT WORK&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/&quot;

&amp;lt;PageTitle&amp;gt;Home&amp;lt;/PageTitle&amp;gt;

&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;

@if (Name is { Length: &amp;gt;0 } name)
{
    &amp;lt;h2&amp;gt;@name&amp;lt;/h2&amp;gt;
}
else
{
    &amp;lt;h2&amp;gt;Welcome to your new app.&amp;lt;/h2&amp;gt;
}

&amp;lt;div class=&quot;my-2&quot;&amp;gt;
    &amp;lt;hr&amp;gt;
    &amp;lt;form action=&quot;&quot; method=&quot;post&quot;&amp;gt;
        &amp;lt;div class=&quot;input-group mb-3&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; class=&quot;form-control&quot; 
                   name=&quot;name&quot; placeholder=&quot;Say your name...&quot;&amp;gt;
            &amp;lt;button
                id=&quot;button-addon2&quot;
                class=&quot;btn btn-outline-secondary&quot;
                type=&quot;submit&quot;&amp;gt;
                Say Hello
            &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;

@code
{
    [SupplyParameterFromForm] public string? Name { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As soon as we submit the page, we get the following error.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;The POST request does not specify which form is being submitted. To fix this, ensure &amp;lt;form&amp;gt; elements have a @formname attribute with any unique value, or pass a FormName parameter if using &amp;lt;EditForm&amp;gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To fix this, we need to add the &lt;code&gt;@formname&lt;/code&gt; SSR attribute and give it a unique name within the page scope.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/&quot;

&amp;lt;PageTitle&amp;gt;Home&amp;lt;/PageTitle&amp;gt;

&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;

@if (Name is { Length: &amp;gt;0} name)
{
    &amp;lt;h2&amp;gt;Hello, @name!&amp;lt;/h2&amp;gt;
}
else
{
    &amp;lt;h2&amp;gt;Welcome to your new app.&amp;lt;/h2&amp;gt;
}

&amp;lt;div class=&quot;my-2&quot;&amp;gt;
    &amp;lt;hr&amp;gt;
    &amp;lt;form action=&quot;&quot; method=&quot;post&quot; @formname=&quot;main&quot;&amp;gt;
        &amp;lt;div class=&quot;input-group mb-3&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; class=&quot;form-control&quot; 
                   name=&quot;name&quot; placeholder=&quot;Say your name...&quot;&amp;gt;
            &amp;lt;button
                id=&quot;button-addon2&quot;
                class=&quot;btn btn-outline-secondary&quot;
                type=&quot;submit&quot;&amp;gt;
                Say Hello
            &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;

@code
{
    [SupplyParameterFromForm] public string? Name { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We still have an issue as you may notice when you submit this form.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Blazor has an &lt;code&gt;AntiforgeryToken&lt;/code&gt; component we forgot to add to the form.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;    &amp;lt;form action=&quot;&quot; method=&quot;post&quot; @formname=&quot;main&quot;&amp;gt;
        &amp;lt;div class=&quot;input-group mb-3&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; class=&quot;form-control&quot; 
                   name=&quot;name&quot; placeholder=&quot;Say your name...&quot;&amp;gt;
            &amp;lt;button
                id=&quot;button-addon2&quot;
                class=&quot;btn btn-outline-secondary&quot;
                type=&quot;submit&quot;&amp;gt;
                Say Hello
            &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;AntiforgeryToken/&amp;gt;
    &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Woot! Now it works. If we look at the HTML rendered to the page, you’ll see what Blazor is doing to transform our form
into one compatible with the Blazor request pipeline.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;form action=&quot;&quot; method=&quot;post&quot;&amp;gt;
&amp;lt;input type=&quot;hidden&quot; name=&quot;_handler&quot; value=&quot;main&quot;&amp;gt;&amp;lt;div class=&quot;input-group mb-3&quot;&amp;gt;&amp;lt;input type=&quot;text&quot; class=&quot;form-control&quot; name=&quot;name&quot; placeholder=&quot;Say your name...&quot;&amp;gt;
            &amp;lt;button id=&quot;button-addon2&quot; class=&quot;btn btn-outline-secondary&quot; type=&quot;submit&quot;&amp;gt;
                Say Hello
            &amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;input type=&quot;hidden&quot; name=&quot;__RequestVerificationToken&quot; value=&quot;CfDJ8LTlmMRHw3JNmUOvTfhPRjst1GbXskBXT7OtvUmsHbD9sMekv4N4xfoGi1hZlx-XqE_xVTjkPJ2U2T_ZN02Z92RfdhmdofvYJYlPn4QwD_Pno-HJ_z6JkjMTtgOcTkO3q72vEYX_Hl9MaHvju50tTz8&quot;&amp;gt;&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;hidden&lt;/code&gt; inputs are notable, as they provide values for &lt;code&gt;_handler&lt;/code&gt; and our antiforgery token.&lt;/p&gt;

&lt;h2 id=&quot;being-extra-with-onsubmit&quot;&gt;Being Extra with @onsubmit&lt;/h2&gt;

&lt;p&gt;I hinted at this in the previous section, but Blazor is processing the “HTML” in our components to inject and add input
elements that we didn’t specify. We can take advantage of another attribute, &lt;code&gt;@onsubmit&lt;/code&gt;, to ensure that all submissions
are handled by the appropriate handler on the page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/&quot;

&amp;lt;PageTitle&amp;gt;Home&amp;lt;/PageTitle&amp;gt;

&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;

@if (Message is not null)
{
    &amp;lt;h2&amp;gt;@Message&amp;lt;/h2&amp;gt;
}
else
{
    &amp;lt;h2&amp;gt;Welcome to your new app.&amp;lt;/h2&amp;gt;
}

&amp;lt;div class=&quot;my-2&quot;&amp;gt;
    &amp;lt;hr&amp;gt;
    &amp;lt;form action=&quot;&quot; method=&quot;post&quot; @formname=&quot;main&quot; @onsubmit=&quot;Submit&quot;&amp;gt;
        &amp;lt;div class=&quot;input-group mb-3&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; class=&quot;form-control&quot; 
                   name=&quot;name&quot; placeholder=&quot;Say your name...&quot;&amp;gt;
            &amp;lt;button
                id=&quot;button-addon2&quot;
                class=&quot;btn btn-outline-secondary&quot;
                type=&quot;submit&quot;&amp;gt;
                Say Hello
            &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;AntiforgeryToken/&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;

@code
{
    [SupplyParameterFromForm(FormName = &quot;main&quot;)] public string? Name { get; set; }
    string? Message { get; set; }

    void Submit()
    {
        if (!string.IsNullOrWhiteSpace(Name))
        {
            Message = $&quot;Hello, {Name} to your Blazor App!&quot;;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice a few new elements in the previous code examples.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Our form now has an &lt;code&gt;@onsubmit&lt;/code&gt; attribute. This allows Blazor to execute the method at the time of a request
according to the &lt;code&gt;_handler&lt;/code&gt; value passed on a submit.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;SupplyParameterFromForm&lt;/code&gt; now has a &lt;code&gt;FormName&lt;/code&gt; property to match our form name. This is optional and only
necessary when dealing with multiple forms on a single page.&lt;/li&gt;
  &lt;li&gt;We have a &lt;code&gt;Submit&lt;/code&gt; method with a bit more complex logic for our component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cool! We have a functioning form on a Blazor SSR page and haven’t sacrificed security or HTML readability. We also now
understand how to add additional forms and handlers as we expand the page’s functionality.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;HTML is great, and using it with ASP.NET Core is pretty great as well. Having Blazor SSR support makes it easy to write
performant server-rendered pages while still maintaining a component-driven approach that so many folks like. I hope you
found this article helpful. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 28 May 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/blazor-html-forms-submitting-and-antiforgery-tokens</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/blazor-html-forms-submitting-and-antiforgery-tokens</guid>
        
        <category>blazor,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Fix Missing OpenAPI Elements From ASP.NET Core Minimal API Apps</title>
        <description>&lt;p&gt;When working in .NET, there’s a lot of room for reorganizing a codebase, but sometimes we can organize ourselves into a
mess of a problem. Recently, when working on an ASP.NET Core Minimal API demo, I seemingly broke an endpoint’s OpenAPI
definition, and it was no longer in the list of endpoints.&lt;/p&gt;

&lt;p&gt;In this short post, we’ll compare two endpoints and discuss why one is different than the other, why it might break
OpenAPI integrations, and how to fix it.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Let’s start with a typical Minimal API endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/hello&quot;, () =&amp;gt;
    {
        return new Hello(&quot;World&quot;);
    })
    .WithName(&quot;Hello&quot;)
    .WithOpenApi();
    
record Hello(string Target);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our endpoint registration contains enough metadata to determine the parameters, the return type and its structure, and
the name of our endpoint. Great! That’s more than enough for ASP.NET Core to generate an OpenAPI definition entry.&lt;/p&gt;

&lt;p&gt;Let’s do some refactoring of our handler to a local function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Task&amp;lt;Hello&amp;gt; Handler()
{
    return Task.FromResult(new Hello(&quot;World&quot;));
}

app.MapGet(&quot;/hello&quot;, Handler)
    .WithName(&quot;Hello&quot;)
    .WithOpenApi();

record Hello(string Target);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, so good! Everything still functions as expected. Now, let’s add a similar endpoint, but we’ll define
an &lt;code&gt;HttpContext&lt;/code&gt; parameter on our endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Task&amp;lt;Hello&amp;gt; HandlerWithContext(HttpContext ctx)
{
    return Task.FromResult(new Hello(&quot;World&quot;));
}

app.MapGet(&quot;/goodbye&quot;, HandlerWithContext)
    .WithName(&quot;Goodbye&quot;)
    .WithOpenApi();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What?! Our OpenAPI endpoint is no longer being generated and is appearing on our definitions page. What happened?!&lt;/p&gt;

&lt;p&gt;If we look at the warning generated by code analysis, we’ll see the culprit.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ASP0016: The method used to create a RequestDelegate returns Task&amp;lt;Hello&amp;gt;. RequestDelegate discards this value.
If this isn’t intended then change the return type to non-generic Task or, if the delegate is a route handler, cast it
to Delegate so the return value is written to the response.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ah! We accidentally turned a method into &lt;code&gt;RequestDelegate&lt;/code&gt; and stripped all the metadata necessary to build our OpenAPI
definition. We can fix that by casting our registration to a delegate.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Task&amp;lt;Hello&amp;gt; HandlerWithContext(HttpContext ctx)
{
    return Task.FromResult(new Hello(&quot;World&quot;));
}

app.MapGet(&quot;/goodbye&quot;, (Delegate)HandlerWithContext)
    .WithName(&quot;Goodbye&quot;)
    .WithOpenApi();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All is good in the world again.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Remember that while code can look very similar syntactically, you may inadvertently strip enough semantics to break
ASP.NET Core’s OpenAPI integration when refactoring your Minimal API endpoints.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/fix-missing-openapi-elements-from-aspnet-core-minimal-api-apps</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/fix-missing-openapi-elements-from-aspnet-core-minimal-api-apps</guid>
        
        <category>csharp,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>ASP.NET Core, SSR Web Components, and Enhance Wasm</title>
        <description>&lt;p&gt;Web components are some of the most exciting technology I’ve seen in a long time. They promise to revolutionize how we
write, maintain, and ship HTML-based applications. With web components, you can extend the set of HTML tags specific to
your site while still providing the functionality you intended with less markup.&lt;/p&gt;

&lt;p&gt;And then there’s Web Assembly, or Wasm for short, a technology that opens up a world of possibilities. It enables all
ecosystems to package functionality in a reusable format that can be deployed across a wide range of platforms.&lt;/p&gt;

&lt;p&gt;Could we combine them to provide ASP.NET Core with brand-new server-side rendering functionality while avoiding the
client-side costs of web components as they attach to the DOM? Sure we can!
With &lt;a href=&quot;https://enhance.dev/wasm&quot;&gt;Enhance Wasm&lt;/a&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-enhance-wasm&quot;&gt;What is Enhance WASM?&lt;/h2&gt;

&lt;p&gt;Enhance WASM is an open-source initiative to bring the features of &lt;a href=&quot;https://enhance.dev/why-enhance&quot;&gt;Enhance&lt;/a&gt;, a dynamic
web apps framework, to the server for all technology stacks through Wasm. As mentioned in the opening, web components
are significant but take some time to attach to an active web page. This can be less than ideal. If we can render some
of the web component’s HTML in advance, we can provide users with a better and faster experience while the page catches
up.&lt;/p&gt;

&lt;p&gt;Web components are a standard way of building components for HTML apps without libraries like React, Angular, Vue, or
Svelte. They are also very lightweight, typically not needing much, if any, build steps. The Enhance project has guiding
tenants that make it appealing for folks suffering from SPA fatigue:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Author and deliver HTML Pages&lt;/li&gt;
  &lt;li&gt;Use Web Standards&lt;/li&gt;
  &lt;li&gt;Progressively enhance working HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ASP.NET Core and Razor are perfect fits for this philosophy as they are mature and reliable technologies. Let’s see how
to get these technologies working together.&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;You’ll first need to download the latest version
of &lt;a href=&quot;https://github.com/enhance-dev/enhance-ssr-wasm&quot;&gt;Enhance WASM from its GitHub page&lt;/a&gt;. Then, place
the &lt;code&gt;enhance-ssr.wasm&lt;/code&gt; file as &lt;code&gt;Content&lt;/code&gt; in an ASP.NET Core application and set it to always copy to your build output
directory.&lt;/p&gt;

&lt;p&gt;Next, install the following packages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;PackageReference Include=&quot;Extism.runtime.all&quot; Version=&quot;1.2.0&quot; /&amp;gt;
  &amp;lt;PackageReference Include=&quot;Extism.Sdk&quot; Version=&quot;1.2.0&quot; /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The SDK package is a wrapper for the runtime packages. Both are required to make the following code work.&lt;/p&gt;

&lt;p&gt;Now we’re ready to write a wrapper for Enhance Wasm.&lt;/p&gt;

&lt;h2 id=&quot;running-enhance-wasm-in-net&quot;&gt;Running Enhance WASM in .NET&lt;/h2&gt;

&lt;p&gt;This part is pretty straightforward. We need to load the &lt;code&gt;enhance-ssr.wasm&lt;/code&gt; file into memory, then load it as an Extism
plugin.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using Extism.Sdk;

namespace EnhanceWebComponents.Services;

public class EnhanceServerSideRenderer(Dictionary&amp;lt;string, string&amp;gt; webComponentElements)
{
    private static readonly byte[] Wasm =
        File.ReadAllBytes(&quot;enhance-ssr.wasm&quot;);

    private readonly Plugin plugin = new(Wasm, [], withWasi: true);

    private static readonly JsonSerializerOptions Options = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    public EnhanceResult Process(EnhanceInput input)
    {
        var value = new EnhanceInputWithComponents(input.Markup, webComponentElements, input.InitialState);
        var json = JsonSerializer.Serialize(value, Options);
        var result = plugin.Call(&quot;ssr&quot;, json);
        
        return result is null
            ? throw new Exception(&quot;unable to process web component&quot;)
            : JsonSerializer.Deserialize&amp;lt;EnhanceResult&amp;gt;(result, Options)!;
    }
}

public record EnhanceInput(
    string Markup,
    object? InitialState = null
);

internal record EnhanceInputWithComponents(
    string Markup,
    Dictionary&amp;lt;string, string&amp;gt; Elements,
    object? InitialState
);

public record EnhanceResult(
    string Document,
    string Body,
    string Styles
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we can call this code with web component definitions and elements to process.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using EnhanceWebComponents.Services;
using Xunit.Abstractions;

namespace EnhanceWebComponents.Tests;

public class EnhanceServerSideRendererTests(ITestOutputHelper output)
{
    private EnhanceServerSideRenderer sut = new(
        webComponentElements: new()
        {
            {
                &quot;my-header&quot;,
                // lang=javascript
                &quot;&quot;&quot;
                function MyHeader({ html }) 
                {
                    return html`&amp;lt;style&amp;gt;h1{color:red;}&amp;lt;/style&amp;gt;&amp;lt;h1&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/h1&amp;gt;` 
                }
                &quot;&quot;&quot;
            },
            {
                &quot;my-component-state&quot;,
                // lang=javascript
                &quot;&quot;&quot;
                function MyComponentState({ html, state }) {
                  const { store } = state
                  return html`&amp;lt;span&amp;gt;${ store?.name }&amp;lt;/span&amp;gt;`
                }
                &quot;&quot;&quot;
            }
        }
    );

    [Fact]
    public void Can_process_web_component()
    {
        var input = new EnhanceInput(
            &quot;&amp;lt;my-header&amp;gt;Hello World&amp;lt;/my-header&amp;gt;&quot;
        );

        var result = sut.Process(input);
        
        output.WriteLine(result.Body);

        Assert.NotNull(result);
        Assert.Equal(&quot;&quot;&quot;&amp;lt;my-header enhanced=&quot;✨&quot;&amp;gt;&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;&amp;lt;/my-header&amp;gt;&quot;&quot;&quot;, result.Body);
        Assert.Equal(&quot;my-header h1 {\n  color: red;\n}&quot;, result.Styles);
    }
    
    [Fact]
    public void Can_process_web_component_with_state()
    {
        var input = new EnhanceInput(
            &quot;&amp;lt;my-component-state&amp;gt;&amp;lt;/my-component-state&amp;gt;&quot;,
            // accessed via state.store.name in JavaScript
            new { name = &quot;Khalid&quot; }
        );

        var result = sut.Process(input);
        
        output.WriteLine(result.Body);

        Assert.NotNull(result);
        Assert.Equal(&quot;&quot;&quot;&amp;lt;my-component-state enhanced=&quot;✨&quot;&amp;gt;&amp;lt;span&amp;gt;Khalid&amp;lt;/span&amp;gt;&amp;lt;/my-component-state&amp;gt;&quot;&quot;&quot;, result.Body);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wooooooooah! It works! Well, it’s nice but it could be nicer. Let’s make a tag helper for ASP.NET Core.&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-enhance-wasm-tag-helper&quot;&gt;ASP.NET Core Enhance Wasm Tag Helper&lt;/h2&gt;

&lt;p&gt;ASP.NET Core has tag helpers that should make this even more awesome, so let’s do that!&lt;/p&gt;

&lt;p&gt;We’ll create two classes: &lt;code&gt;EnhanceTagHelper&lt;/code&gt; and &lt;code&gt;EnhanceRequestContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace EnhanceWebComponents.Services;

[HtmlTargetElement(Attributes = EnhanceSsrAttribute)]
public class EnhanceTagHelper(EnhanceServerSideRenderer enhanceServerSideRenderer, EnhanceRequestContext enhanceCtx) : TagHelper
{
    private const string EnhanceSsrAttribute = &quot;enhance-ssr&quot;; 
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        output.Attributes.Clear();
        foreach (var attribute in context.AllAttributes)
        {
            if (attribute.Name == &quot;enhance-ssr&quot;)
                continue;
            
            output.Attributes.Add(attribute);
        }
        output.Content = await output.GetChildContentAsync();

        var sb = new StringBuilder();
        await using var stringWriter = new StringWriter(sb);
        output.WriteTo(stringWriter, HtmlEncoder.Default);

        var input = new EnhanceInput(sb.ToString());
        
        var result = enhanceServerSideRenderer.Process(input);
        // remove outer-wrapper
        output.TagName = &quot;&quot;;
        output.Content.SetHtmlContent(result.Body);
        
        // any scoped css goes into the current context
        enhanceCtx.Add(result);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You notice the type &lt;code&gt;EnhanceRequestContext&lt;/code&gt;; this request-scoped instance allows us to push processed CSS into memory
while all the components are being processed.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Collections.Concurrent;
using System.Text;
using Microsoft.AspNetCore.Html;

namespace EnhanceWebComponents.Services;

public class EnhanceRequestContext
{
    private ConcurrentBag&amp;lt;EnhanceResult&amp;gt; Results { get; }
        = new();

    public void Add(EnhanceResult result) =&amp;gt;
        Results.Add(result);
    
    public IHtmlContent Styles()
    {
        return new HtmlString(
            // lang=html
            $&quot;&quot;&quot;
             &amp;lt;style enhanced=&quot;✨&quot;&amp;gt;
                {GetAllStyles()}
             &amp;lt;/style&amp;gt;
             &quot;&quot;&quot;
        );
    }
    
    private string GetAllStyles()
    {
        var sb = new StringBuilder();
        // we only want the unique styles
        foreach (var result in Results.DistinctBy(x =&amp;gt; x.Styles)) 
            sb.AppendLine(result.Styles);
        return sb.ToString();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s register these types in &lt;code&gt;Program.cs&lt;/code&gt; in our services collection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddSingleton(new EnhanceServerSideRenderer(
    // Note: pull these definitions from somewhere else.
    // you could probably read these from a folder in `wwwroot/js` 
    // and register them by convention `name of file` and `contents`.
    webComponentElements: new()
    {
        {
            &quot;my-header&quot;,
            // lang=javascript
            &quot;&quot;&quot;
            function MyHeader({ html }) 
            {
                return html`&amp;lt;style&amp;gt;h1{color:purple;}&amp;lt;/style&amp;gt;&amp;lt;h1&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/h1&amp;gt;` 
            }
            &quot;&quot;&quot;
        }
    }
));

// a &quot;per request&quot; entity to store results so you 
// can then spit out the scoped CSS styles where you need them
builder.Services.AddScoped&amp;lt;EnhanceRequestContext&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must also inform Razor about our new tag helper in &lt;code&gt;_ViewImports.cshtml&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@using EnhanceWebComponents
@namespace EnhanceWebComponents.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, EnhanceWebComponents
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also update our &lt;code&gt;_Layout.cshtml&lt;/code&gt; file to use the &lt;code&gt;EnhanceRequestContext&lt;/code&gt; to render the CSS. Since
the &lt;code&gt;_Layout.cshtml&lt;/code&gt; is processed last, we know all web components will have already been processed in our views.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@using EnhanceWebComponents.Services
@inject EnhanceRequestContext Enhance

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;/&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&amp;gt;
    &amp;lt;title&amp;gt;@ViewData[&quot;Title&quot;] - EnhanceWebComponents&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/lib/bootstrap/dist/css/bootstrap.min.css&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/css/site.css&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/EnhanceWebComponents.styles.css&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    @Enhance.Styles()
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note: if you want to process web components in the &lt;code&gt;_Layout.cshtml&lt;/code&gt; file, they will work, but you need to get any
scoped CSS into the collection. This can be done using middleware or some other pre-layout processing.&lt;/strong&gt; This is an edge
case, and I thought it was overkill for a proof of concept.&lt;/p&gt;

&lt;p&gt;Finally, we can use the tag helper and our server-side rendered web components in any Razor view.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page
@model IndexModel
@{
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;
}

&amp;lt;div class=&quot;text-center&quot;&amp;gt;
    &amp;lt;my-header class=&quot;display-4&quot; enhance-ssr&amp;gt;Hello World&amp;lt;/my-header&amp;gt;
    &amp;lt;my-header class=&quot;display-3&quot; enhance-ssr&amp;gt;Hello Again&amp;lt;/my-header&amp;gt;
    &amp;lt;p&amp;gt;Learn about &amp;lt;a href=&quot;https://learn.microsoft.com/aspnet/core&quot;&amp;gt;
        building Web apps with ASP.NET Core
    &amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the resulting HTML being what we expected.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div class=&quot;text-center&quot;&amp;gt;
    &amp;lt;my-header class=&quot;display-4&quot; enhanced=&quot;✨&quot;&amp;gt;&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;&amp;lt;/my-header&amp;gt;
    &amp;lt;my-header class=&quot;display-3&quot; enhanced=&quot;✨&quot;&amp;gt;&amp;lt;h1&amp;gt;Hello Again&amp;lt;/h1&amp;gt;&amp;lt;/my-header&amp;gt;
    &amp;lt;p&amp;gt;Learn about &amp;lt;a href=&quot;https://learn.microsoft.com/aspnet/core&quot;&amp;gt;
        building Web apps with ASP.NET Core
    &amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;along with the aggregated &lt;code&gt;style&lt;/code&gt; element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;style enhanced=&quot;✨&quot;&amp;gt;
my-header h1 {
  color: purple;
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you’re interested in trying this, I’ve made the *
*&lt;a href=&quot;https://github.com/khalidabuhakmeh/EnhanceWebComponents&quot;&gt;code available on GitHub&lt;/a&gt;**. I haven’t thought out some edge
cases, like the &lt;code&gt;_Layout.cshtml&lt;/code&gt; processing, and what to do with attributes in Razor vs. the ones on web components.
That said, there’s a lot of potential here for providing an experience never before seen for ASP.NET Core developers.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing this post with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 14 May 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/aspnet-core-ssr-web-components-and-enhance-wasm</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/aspnet-core-ssr-web-components-and-enhance-wasm</guid>
        
        <category>aspnet,</category>
        
        <category>wasm,</category>
        
        <category>web</category>
        
        
      </item>
    
      <item>
        <title>How to add HTTP headers to Blazor Components with RazorComponentResult</title>
        <description>&lt;p&gt;In a previous post, ]I wrote about using &lt;code&gt;RazorComponentResult&lt;/code&gt; to render Blazor components](/how-to-use-blazor-server-rendered-components-with-htmx) from ASP.NET Core Minimal APIs. The ability allows
developers to reuse Blazor components in new and exciting scenarios, specifically with JavaScript UI frameworks and
libraries such as React, Vue, Angular, and my favorite library, &lt;a href=&quot;https://htmx.org&quot;&gt;HTMX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this concise post, we’ll explore setting HTTP Headers for &lt;code&gt;RazorComponentResult&lt;/code&gt; and creating an extension method
that simplifies this task, making your development process more efficient.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;razorcomponentresult-recap&quot;&gt;RazorComponentResult Recap&lt;/h2&gt;

&lt;p&gt;Blazor is a component-driven development framework inspired by the &lt;a href=&quot;https://react.dev&quot;&gt;JavaScript React library&lt;/a&gt;.
Components aim to encapsulate UI elements into reusable elements to help accelerate development. They can vary in size,
from buttons, links, and textboxes to logical components such as detail cards, tables, video elements, and so on.&lt;/p&gt;

&lt;p&gt;Component trees also help manage a page’s state, and Blazor provides some DOM diffing capabilities similar to React. The
aim is to make pages more responsive and performant to user interactions without unnecessary DOM swaps. This feature
expects components to be nested in other components until you reach the parent component, typically a page. But what
about using Blazor for HTML fragments?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RazorComponentResult&lt;/code&gt; allows ASP.NET Core endpoints to generate HTML &lt;strong&gt;server-side&lt;/strong&gt; from Blazor components. This can
help build HTML APIs for other JavaScript frameworks or vanilla JavaScript calls from your client UI. Let’s see what it
looks like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/vanilla&quot;,
    () =&amp;gt; new RazorComponentResult&amp;lt;LoveHtmx&amp;gt;(new
    {
        Message = &quot;I ❤️ ASP.NET Core&quot;
    }));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The corresponding component of &lt;code&gt;LoveHtmx&lt;/code&gt; is what you’d expect a Blazor component to look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
    &amp;lt;span class=&quot;text-lg-center&quot;&amp;gt;
        @Message
    &amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

@code{
    [Parameter]
    public string? Message { get; set; } = &quot;I ❤️ HTMX&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! Now that we’re all caught back up, how do we set these HTTP headers?&lt;/p&gt;

&lt;h2 id=&quot;httpcontext-and-server-side-blazor-components&quot;&gt;HttpContext and Server-Side Blazor Components&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;RazorComponentResult&lt;/code&gt; generates the HTML that would accompany a Blazor component. While it’s essential to recognize
this approach’s limitations, those limitations allow us to make some advantageous assumptions.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Blazor Components must be completely rendered on the server, with no interactivity. I’m sorry, but you’re not getting
SignalR or Wasm here.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;RazorComponentResult&lt;/code&gt; manages the entire &lt;code&gt;Response&lt;/code&gt; lifecycle.&lt;/li&gt;
  &lt;li&gt;You need to specify the state of the component at render time.&lt;/li&gt;
  &lt;li&gt;You get access to all the server goodies, like &lt;code&gt;HttpContext&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, let’s first do the &lt;strong&gt;wrong&lt;/strong&gt; thing. This does not work ❌.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/vanilla&quot;,
    (HttpContext ctx) =&amp;gt;
    {
        ctx.Response.Headers.Append(&quot;Nope&quot;, &quot;Fail&quot;);
        
        return new RazorComponentResult&amp;lt;LoveHtmx&amp;gt;(new
        {
            Message = &quot;I ❤️ ASP.NET Core&quot;
        });
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will fail if you try to set HTTP headers from your ASP.NET Core Minimal API endpoint. Remember, the
RazorComponentResult manages the entire Response state. How do we get what we want?&lt;/p&gt;

&lt;p&gt;First, we must add an &lt;code&gt;IHttpContextAccessor&lt;/code&gt; to our services collection in our &lt;code&gt;Program&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddHttpContextAccessor();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s get to the component. We need to set headers in the component using the &lt;code&gt;HttpContext&lt;/code&gt;instance, which we’ll
get from an &lt;code&gt;IHttpContextAccessor&lt;/code&gt;. We can inject the instance using the &lt;code&gt;InjectAttribute&lt;/code&gt; or the &lt;code&gt;@inject&lt;/code&gt; declaration.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;
&amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
    &amp;lt;span class=&quot;text-lg-center&quot;&amp;gt;
        @Message
    &amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

@code{
    [Parameter] public string? Message { get; set; } = &quot;I ❤️ HTMX&quot;;

    [Parameter]
    public IHeaderDictionary? Headers { get; set; }
        = new HeaderDictionary();

    [Inject] public IHttpContextAccessor? HttpContextAccessor { get; set; }

    protected override Task OnInitializedAsync()
    {
        if (HttpContextAccessor?.HttpContext is { } ctx &amp;amp;&amp;amp;
            Headers is not null)
        {
            foreach (var (key, value) in Headers)
            {
                ctx.Response.Headers.Append(key, value);
            }
        }

        return base.OnInitializedAsync();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or you might prefer this approach.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@inject IHttpContextAccessor HttpContextAccessor

&amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;
    &amp;lt;span class=&quot;text-lg-center&quot;&amp;gt;
        @Message
    &amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

@code{
    [Parameter] public string? Message { get; set; } = &quot;I ❤️ HTMX&quot;;

    [Parameter]
    public IHeaderDictionary? Headers { get; set; }
        = new HeaderDictionary();

    protected override Task OnInitializedAsync()
    {
        if (HttpContextAccessor?.HttpContext is { } ctx &amp;amp;&amp;amp;
            Headers is not null)
        {
            foreach (var (key, value) in Headers)
            {
                ctx.Response.Headers.Append(key, value);
            }
        }

        return base.OnInitializedAsync();
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This component will only work as a server-rendered component since &lt;code&gt;HttpContext&lt;/code&gt; is a dependency.&lt;/p&gt;

&lt;p&gt;We can now also write an excellent extension method to keep us from making previous mistakes in the future.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class RazorComponentResultExtensions
{
    public static RouteHandlerBuilder MapGetRazorComponent&amp;lt;TComponent&amp;gt;(
        this IEndpointRouteBuilder endpoints,
        [StringSyntax(&quot;Route&quot;)] string pattern,
        object? state = null
    )
        where TComponent : IComponent
    {
        var dictionary = new RouteValueDictionary(state);
        return endpoints.MapGet(pattern, () =&amp;gt; new RazorComponentResult&amp;lt;TComponent&amp;gt;(dictionary));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And our new registration now looks like this.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGetRazorComponent&amp;lt;LoveHtmxWithHeader&amp;gt;(
    &quot;/love-htmx&quot;,
    new
    {
        Message = &quot;I ❤️ ASP.NET Core&quot;,
        Headers = new HeaderDictionary
        {
            { &quot;Hx-Trigger&quot;, &quot;blazor-x&quot; }
        }
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you have it. You can now set HTTP headers when using &lt;code&gt;RazorComponentResult&lt;/code&gt;. Using the extension method I provided
also makes it clear not to add any additional code in your endpoints, helping you avoid the chance of introducing bugs.
Give it a shot!&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts with friends and colleagues. As always, cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 May 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-add-http-headers-to-blazor-components-with-razorcomponentresult</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-add-http-headers-to-blazor-components-with-razorcomponentresult</guid>
        
        <category>blazor,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Working with Rust Libraries from C# .NET Applications</title>
        <description>&lt;p&gt;I’ve been on a Rust learning journey lately, and it’s had me thinking about how I can consume Rust libraries from
existing .NET applications. The .NET team has done much work regarding interoperability during the .NET 6 to .NET 8 era,
and .NET 9 seems poised to continue that trend.&lt;/p&gt;

&lt;p&gt;In this post, we’ll create a Rust library and consume it from a .NET application. This post assumes you have installed
the .NET SDK and Rust SDK (cargo).&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;a-simple-rust-library&quot;&gt;A Simple Rust Library&lt;/h2&gt;

&lt;p&gt;After creating a .NET Solution, I first created a new Rust library using &lt;code&gt;cargo&lt;/code&gt;. The command is relatively
straightforward.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cargo init --lib calculator
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a new &lt;code&gt;calculator&lt;/code&gt; library folder with the most critical files: &lt;code&gt;Cargo.toml&lt;/code&gt; and &lt;code&gt;lib.rs&lt;/code&gt;. Let’s update
the &lt;code&gt;Cargo.toml&lt;/code&gt; file to produce an artifact that our .NET application can consume, a dynamic library.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;[package]
name = &quot;calculator&quot;
version = &quot;0.1.0&quot;
edition = &quot;2021&quot;

[lib]
name=&quot;calculator&quot;
crate-type=[&quot;dylib&quot;]

[dependencies]
rand = &quot;0.8.5&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ve also included the &lt;code&gt;rand&lt;/code&gt; dependency for my Rust code later. Running the &lt;code&gt;cargo b&lt;/code&gt; command will now produce a
library we can copy into our .NET application.&lt;/p&gt;

&lt;p&gt;Let’s write some Rust code we’ll consume from our .NET application later.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use rand::prelude::*;
use std::ffi::{c_char, CStr};

#[repr(C)]
#[derive(Debug)]
pub struct Point {
    pub x: u32,
    pub y: u32,
}

#[no_mangle]
pub extern &quot;C&quot; fn add(left: usize, right: usize) -&amp;gt; usize {
    left + right
}

#[no_mangle]
pub extern &quot;C&quot; fn say_hello(name: *const c_char) {
    let c_str = unsafe { CStr::from_ptr(name) };
    println!(&quot;Hello, {}&quot;, c_str.to_str().unwrap())
}

#[no_mangle]
pub extern &quot;C&quot; fn random_point() -&amp;gt; Point {
    let mut rng = rand::thread_rng();
    Point {
        x: rng.gen::&amp;lt;u32&amp;gt;(),
        y: rng.gen::&amp;lt;u32&amp;gt;(),
    }
}

#[no_mangle]
pub extern &quot;C&quot; fn distance(first: &amp;amp;Point, second: &amp;amp;Point) -&amp;gt; f64 {
    let dx: f64 = (second.x - first.x).into();
    let dy: f64 = (second.y - first.y).into();

    println!(&quot;calculating distance...&quot;);

    (dx.powf(2.0) + dy.powf(2.0)).sqrt()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    fn say_hello_test() {
        let _result = say_hello(&quot;Khalid&quot;.as_ptr() as *const i8);

        assert!(true)
    }

    #[test]
    fn get_random_point() {
        let point: Point = random_point();
        println!(&quot;{:?}&quot;, point);
        assert!(true);
    }

    #[test]
    fn can_calculate_distance() {
        let one = Point { x: 1, y: 1 };
        let two = Point { x: 2, y: 2 };

        let result = distance(&amp;amp;one, &amp;amp;two);
        println!(&quot;distance between {:?} and {:?} is {}&quot;, one, two, result);
        assert!((result - 1.414).abs() &amp;lt; 0.001)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notable elements of this Rust code include the following.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;code&gt;extern&lt;/code&gt; keyword adds to the list of functions and types in the foreign functions interfaces (FFI).&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;no_mangle&lt;/code&gt; tells the Rust compiler not to mangle the function’s name so that it can be referenced externally by a
.NET application or similar external consumer.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;&quot;C&quot;&lt;/code&gt; value after &lt;code&gt;extern&lt;/code&gt; tells the Rust compiler to compile to something C-compatible. There are other options
here as well.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;repr&lt;/code&gt; attribute on &lt;code&gt;Point&lt;/code&gt; states that this structure should be stored in memory in a C-compatible way.&lt;/li&gt;
  &lt;li&gt;All functions should use references to elements, which allows us to marshal information from one technology stack to
another with little to no overhead. You need to be careful not to introduce memory leaks here, hence the use
of &lt;code&gt;unsafe&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now let’s modify our .NET application for some Rust fun.&lt;/p&gt;

&lt;h2 id=&quot;building-rust-from-a-net-project&quot;&gt;Building Rust from a .NET Project&lt;/h2&gt;

&lt;p&gt;I’ve used this trick several times across tools, and it works like a charm here with Rust. You can use the MSBuild task
of &lt;code&gt;Exec&lt;/code&gt; to execute commands.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&amp;gt;

  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;LangVersion&amp;gt;preview&amp;lt;/LangVersion&amp;gt;
    &amp;lt;OutputType&amp;gt;Exe&amp;lt;/OutputType&amp;gt;
    &amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;
    &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
    &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
    &amp;lt;AllowUnsafeBlocks&amp;gt;true&amp;lt;/AllowUnsafeBlocks&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;

  &amp;lt;Target Name=&quot;Rust Build &quot; BeforeTargets=&quot;Compile&quot;&amp;gt;
    &amp;lt;Exec Command=&quot;echo &apos;Configuration: $(Configuration)&apos;&quot;/&amp;gt;
    &amp;lt;Exec Condition=&quot;&apos;$(Configuration)&apos; == &apos;Release&apos;&quot; Command=&quot;cargo b --release&quot; WorkingDirectory=&quot;./../calculator&quot;/&amp;gt;
    &amp;lt;Exec Condition=&quot;&apos;$(Configuration)&apos; != &apos;Release&apos;&quot; Command=&quot;cargo b&quot; WorkingDirectory=&quot;./../calculator&quot;/&amp;gt;
  &amp;lt;/Target&amp;gt;

  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;PackageReference Include=&quot;Spectre.Console&quot; Version=&quot;0.48.1-preview.0.38&quot;/&amp;gt;
    &amp;lt;Content Include=&quot;../calculator/target/$(Configuration)/libcalculator.dylib&quot;&amp;gt;
      &amp;lt;CopyToOutputDirectory&amp;gt;PreserveNewest&amp;lt;/CopyToOutputDirectory&amp;gt;
    &amp;lt;/Content&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;


&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll also need to set the &lt;code&gt;AllowUnsafeBlocks&lt;/code&gt; element to &lt;code&gt;true&lt;/code&gt;, or you won’t be able to access any library. Every
time we compile, we’ll build our Rust library and copy it to the project root. From there, we’ll copy the library to our
output directory for each build. Depending on your project, feel free to change when the Rust build occurs.&lt;/p&gt;

&lt;p&gt;Let’s write some C# code.&lt;/p&gt;

&lt;h2 id=&quot;calling-rust-from-c&quot;&gt;Calling Rust from C#&lt;/h2&gt;

&lt;p&gt;Now, it’s just a matter of giving our C# code something to call. We can do this using .NET’s &lt;code&gt;LibraryImportAttribute&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public partial class Rust
{
    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;add&quot;)]
    public static partial int Add(int left, int right);

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;say_hello&quot;
        , StringMarshalling = StringMarshalling.Utf8)]
    public static partial void SayHello(string name);

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;random_point&quot;)]
    public static partial Point GetRandomPoint();

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;distance&quot;)]
    public static partial double Distance(ref Point one, ref Point two);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[DebuggerDisplay(&quot;({X}, {Y})&quot;)]
public struct Point
{
    public UInt32 X;
    public UInt32 Y;
    public override string ToString()
        =&amp;gt; $&quot;(x: {X}, y: {Y})&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Your interface must match the expectations set by the Rust library. Things like structures, types, and references must
match, or you’ll likely get an error code of 139, and the executing application will halt.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Diagnostics;
using System.Runtime.InteropServices;
using Spectre.Console;

var one = new Point { X = 1, Y = 1 };
var two = new Point { X = 2, Y = 2 };

var distance = Rust.Distance(ref one, ref two);
AnsiConsole.MarkupLine($&quot;Distance between [yellow]{one}[/] and [red]{two}[/] is [green]{distance}[/]&quot;);

var (left, right) = (2, 2);
var result = Rust.Add(left, right);

AnsiConsole.MarkupLine($&quot;[yellow]{left} + {right}[/] = [green]{result}![/]&quot;);
Rust.SayHello(&quot;Khalid&quot;);
AnsiConsole.MarkupInterpolated($&quot;[red]{Rust.GetRandomPoint()}[/]&quot;);

public partial class Rust
{
    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;add&quot;)]
    public static partial int Add(int left, int right);

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;say_hello&quot;
        , StringMarshalling = StringMarshalling.Utf8)]
    public static partial void SayHello(string name);

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;random_point&quot;)]
    public static partial Point GetRandomPoint();

    [LibraryImport(&quot;libcalculator&quot;, EntryPoint = &quot;distance&quot;)]
    public static partial double Distance(ref Point one, ref Point two);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[DebuggerDisplay(&quot;({X}, {Y})&quot;)]
public struct Point
{
    public UInt32 X;
    public UInt32 Y;
    public override string ToString()
        =&amp;gt; $&quot;(x: {X}, y: {Y})&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;LibraryImport&lt;/code&gt; works with the &lt;code&gt;DllImportAttribute&lt;/code&gt; and is a source generator that correctly handles common memory
management issues with marshaling types like &lt;code&gt;string&lt;/code&gt; or reference types. You should use &lt;code&gt;LibraryImport&lt;/code&gt; instead of
writing the &lt;code&gt;DllImport&lt;/code&gt; code yourself.&lt;/p&gt;

&lt;p&gt;The results are as you’d expect.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;calculating distance...
Distance between (x: 1, y: 1) and (x: 2, y: 2) is 1.4142135623730951
2 + 2 = 4!
Hello, Khalid
(x: 2497287370, y: 698299366)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you have it. We could call Rust code from a .NET Application with different levels of complexity. That’s pretty
cool!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I want to thank &lt;a href=&quot;https://dev.to/living_syn/calling-rust-from-c-6hk&quot;&gt;Jeremy Mill&lt;/a&gt;, who wrote a blog post 2017 that helped
me learn and experiment with this sample. I hope you found this post helpful, and be sure to share it with friends and
colleagues. As always, thanks and cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/working-with-rust-libraries-from-csharp-dotnet-applications</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/working-with-rust-libraries-from-csharp-dotnet-applications</guid>
        
        <category>rust,</category>
        
        <category>dotnet,</category>
        
        <category>csharp</category>
        
        
      </item>
    
      <item>
        <title>Fix Unable To Resolve DbContextOptions For EF Core</title>
        <description>&lt;p&gt;I recently hosted
a &lt;a href=&quot;https://www.youtube.com/watch?v=N_eLotlcjXo&quot;&gt;live stream with badass-as-a-service Chris Klug, titled “Stop using Entity Framework Core as a DTO Provider!”&lt;/a&gt;.
It’s worth a watch, and it gave me, a long-time Entity Framework user, a lot to think about and reevaluate in my
workflows. That said, regardless of whether you agree with Chris’ style, he showed a masterclass of tool usage and an
understanding that’s easy to admire. In our live stream, one new trick (to me, at least) stood out as something every
Entity Framework Core user should know about.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore one strategy to appease the &lt;code&gt;dotnet ef&lt;/code&gt; CLI tools regarding design-time configuration and
how it opens up a world of possibilities when dealing with database migrations.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;dependencies-and-ceremony&quot;&gt;Dependencies and ceremony&lt;/h2&gt;

&lt;p&gt;Entity Framework Core is heavily built around conventions and flexibility. It’s a multi-provider object-relational
mapper (ORM), so it needs to operate under many unknown factors, with you, the developer, filling in the gaps. What
database are you using? How many databases are you targeting? What migration strategies are you applying? The
flexibility is excellent for solving complex problems but also leads developers into the woods of opaque exceptions.&lt;/p&gt;

&lt;p&gt;One such problem you’ve likely encountered is the following error output when using the &lt;code&gt;dotnet ef migrations add&lt;/code&gt;
command.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Unable to create a &apos;DbContext&apos; of type &apos;&apos;. The exception 
&apos;Unable to resolve service for type 
&apos;Microsoft.EntityFrameworkCore.DbContextOptions`1[MigrationLibrary.Database]&apos;
while attempting to activate &apos;MigrationLibrary.Database&apos;.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;DbContextOptions&lt;/code&gt; class is used to configure a &lt;code&gt;DbContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;

namespace MigrationLibrary;

public class Database(DbContextOptions&amp;lt;Database&amp;gt; options) 
    : DbContext(options)
{
    public DbSet&amp;lt;Person&amp;gt; People =&amp;gt; Set&amp;lt;Person&amp;gt;();
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; } = &quot;&quot;;
    public int Age { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Everything looks good, but we need to see the &lt;code&gt;OnConfiguring&lt;/code&gt; implementation here, which adds the necessary answers to
which database we hope to use. Let’s tweak the code to solve this issue.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;

namespace MigrationLibrary;

public class Database() : DbContext 
{
    public DbSet&amp;lt;Person&amp;gt; People =&amp;gt; Set&amp;lt;Person&amp;gt;();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite();
    }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; } = &quot;&quot;;
    public int Age { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The error is gone now, but we’ve locked into options we can no longer configure outside the &lt;code&gt;Database&lt;/code&gt; class. We want
something else.&lt;/p&gt;

&lt;p&gt;We still want to be able to pass in a &lt;code&gt;DbContextOptions&lt;/code&gt; instance. This allows us to configure the &lt;code&gt;DbContext&lt;/code&gt; to point
to different database implementations and connection strings and alter logging options. We want all that, trust me.&lt;/p&gt;

&lt;p&gt;Let’s use a little-known feature to fix this: &lt;code&gt;IDesignTimeDbContextFactory&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;idesigntimedbcontextfactory-to-the-rescue&quot;&gt;IDesignTimeDbContextFactory to the rescue&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;IDesignTimeDbContextFactory&lt;/code&gt; is a tool that can change how you write migrations, and I don’t say this lightly.
Let’s look at the documentation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;A factory for creating derived DbContext instances. 
Implement this interface to enable design-time services 
for context types that do not have a public default constructor.
At design-time, derived DbContext instances can be created 
in order to enable specific design-time experiences such 
as Migrations.
 
Design-time services will automatically discover 
implementations of this interface that are in the 
startup assembly or the same assembly as the derived context.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hmmm, nice. So what does that look like in C#?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace MigrationLibrary.Configuration;

// ReSharper disable once UnusedType.Global
public class DatabaseDesignTimeDbContextFactory 
    : IDesignTimeDbContextFactory&amp;lt;Database&amp;gt;
{
    public Database CreateDbContext(string[] args)
    {
        var builder = new DbContextOptionsBuilder&amp;lt;Database&amp;gt;();
        builder.UseSqlite();
        return new Database(builder.Options);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Adding this class definition to your project lets Entity Framework’s design-time services answer some of the questions
needed to generate migrations and other configuration options.&lt;/p&gt;

&lt;p&gt;Running the &lt;code&gt;dotnet ef migrations add&lt;/code&gt; command now results in the following output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;(base) ~/RiderProjects/MigrationLibrary
dotnet ef migrations add --project MigrationLibrary AddPerson
Build started...
Build succeeded.
Done. To undo this action, use &apos;ef migrations remove&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, you can define all your migrations and the database configuration in one project while still allowing consuming
projects to modify and change options within reason (i.e., you can’t apply SQLite migrations to a SQL Server database).&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I love doing live streams because I get to learn from some of the best .NET professionals in the industry, and Chris
Klug didn’t disappoint. &lt;a href=&quot;https://www.youtube.com/watch?v=N_eLotlcjXo&quot;&gt;Again, I highly recommend you watch the stream.&lt;/a&gt;
This tip, amongst others, is sprinkled throughout the presentation. As always, thanks for reading and sharing these
posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/fix-unable-to-resolve-dbcontextoptions-for-ef-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/fix-unable-to-resolve-dbcontextoptions-for-ef-core</guid>
        
        <category>entity-framework,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Event Queues and Buffering Functions with JavaScript</title>
        <description>&lt;p&gt;I was testing JetBrains’
latest &lt;a href=&quot;https://plugins.jetbrains.com/plugin/14823-full-line-code-completion&quot;&gt;Full Line Code Completion plugin&lt;/a&gt;
in &lt;a href=&quot;https://jetbrains.com/webstorm&quot;&gt;WebStorm&lt;/a&gt; by writing a quick JavaScript demo, and by the end, I was pretty happy
with what I had built. The JavaScript uses a queue that pushes events to change classes on buttons in &lt;code&gt;250ms&lt;/code&gt; intervals
to create a smooth color transition from one style to another.&lt;/p&gt;

&lt;p&gt;Is it practical? I don’t know, but it sure is fun. I’ve included all the demo’s contents in a single file so you can
test it locally. By the end of this post, you’ll have seen an event queue and how to use it in your JavaScript.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;write-a-javascript-event-queue&quot;&gt;Write a JavaScript Event Queue&lt;/h2&gt;

&lt;p&gt;The premise of my event queue is straightforward. Push events into a queue and have them execute on a set universal
interval. I also wanted the ability to &lt;code&gt;clear&lt;/code&gt; the queue of any remaining events.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class EventQueue {
    constructor(interval) {
        this.queue = [];
        this.interval = interval;
        this.startProcessing();
    }

    enqueue(eventFunction) {
        this.queue.push(eventFunction);
    }

    clear() {
        this.queue = [];
    }

    startProcessing() {
        setInterval(() =&amp;gt; {
            if (this.queue.length &amp;gt; 0) {
                const eventFunction = this.queue.shift();
                eventFunction();
            }
        }, this.interval);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use the &lt;code&gt;setInterval&lt;/code&gt; function to check the queue at our designated interval to process any remaining events. Let’s
start using it.&lt;/p&gt;

&lt;h2 id=&quot;transitioning-button-colors-on-mouse-move&quot;&gt;Transitioning Button Colors on Mouse Move&lt;/h2&gt;

&lt;p&gt;Before we write some more JavaScript, let’s look at the HTML elements we’ll change. Note that I’m using the &lt;strong&gt;Bulma&lt;/strong&gt;
CSS library and its button styling classes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div class=&quot;columns&quot;&amp;gt;
    &amp;lt;div class=&quot;column&quot;&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-info&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-success&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-warning&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-danger&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-primary&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-link&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-info&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-success&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-warning&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-danger&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-primary&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;m-1 button is-link&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, to smooth the transition between styles, I wrote an additional CSS style to ease the &lt;code&gt;background-color&lt;/code&gt; to limit
the strobing effect that might happen if colors change too quickly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;style&amp;gt;
    .button {
        transition: background-color 0.2s ease-in-out;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s write some JavaScript. We want to change the CSS class on each &lt;code&gt;.button&lt;/code&gt; as the user moves the mouse. If the user
stops moving the mouse or leaves the bounds of the page, we want to clear all remaining events from our queue.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;window.addEventListener(&apos;DOMContentLoaded&apos;, () =&amp;gt; {

    const colors = [
        &quot;is-info&quot;, &quot;is-success&quot;,
        &quot;is-warning&quot;, &quot;is-danger&quot;,
        &quot;is-primary&quot;, &quot;is-link&quot;
    ];

    const queue = new EventQueue(250 /* ms */);
    const changeButtonColors = () =&amp;gt; {
        const buttons = document.querySelectorAll(&quot;.button&quot;);
        buttons.forEach(button =&amp;gt; {
            button.classList.forEach((c) =&amp;gt; {
                if (c.startsWith(&quot;is-&quot;)) {
                    const currentIndex = colors.indexOf(c);
                    const newIndex = currentIndex &amp;lt; colors.length - 1
                        ? currentIndex + 1 : 0;
                    button.classList.remove(c);
                    button.classList.add(colors[newIndex]);
                }
            });
        });
    };

    document.addEventListener(&apos;mousemove&apos;, (e) =&amp;gt; {
        if (e.movementX === 0 &amp;amp;&amp;amp; e.movementY === 0) {
            queue.clear();
        } else {
            queue.enqueue(changeButtonColors);
        }
    });

    document.addEventListener(&apos;mouseleave&apos;, () =&amp;gt; {
        queue.clear();
    })
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s pretty straightforward. As a personal side note, JavaScript and the web stack have come a long way. This was
genuinely a joy to write.&lt;/p&gt;

&lt;p&gt;Let’s see what it’s like in action.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;metadata&quot; style=&quot;width:100%&quot;&gt;
    &lt;source src=&quot;/assets/images/posts/misc/event-queue-mar12-2024.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Pretty cool!&lt;/p&gt;

&lt;p&gt;Here’s the full HTML/JavaScript/CSS combination in one file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
    &amp;lt;!-- bulma.io --&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.4/css/bulma.min.css&quot;&amp;gt;
    &amp;lt;style&amp;gt;
        .button {
            transition: background-color 0.2s ease-in-out;
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;section class=&quot;section&quot;&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
        &amp;lt;h1 class=&quot;title&quot;&amp;gt;
            Hello World
        &amp;lt;/h1&amp;gt;
        &amp;lt;p class=&quot;subtitle&quot;&amp;gt;
            My first website with &amp;lt;strong&amp;gt;Bulma&amp;lt;/strong&amp;gt;!
        &amp;lt;/p&amp;gt;
        &amp;lt;div class=&quot;columns&quot;&amp;gt;
            &amp;lt;div class=&quot;column&quot;&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-info&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-success&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-warning&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-danger&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-primary&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-link&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-info&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-success&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-warning&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-danger&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-primary&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
                &amp;lt;button class=&quot;m-1 button is-link&quot;&amp;gt;🐁 Move&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/section&amp;gt;
&amp;lt;script type=&quot;application/javascript&quot;&amp;gt;
window.addEventListener(&apos;DOMContentLoaded&apos;, () =&amp;gt; {

    const colors = [
        &quot;is-info&quot;, &quot;is-success&quot;,
        &quot;is-warning&quot;, &quot;is-danger&quot;,
        &quot;is-primary&quot;, &quot;is-link&quot;
    ];

    const queue = new EventQueue(250 /* ms */);
    const changeButtonColors = () =&amp;gt; {
        const buttons = document.querySelectorAll(&quot;.button&quot;);
        buttons.forEach(button =&amp;gt; {
            button.classList.forEach((c) =&amp;gt; {
                if (c.startsWith(&quot;is-&quot;)) {
                    const currentIndex = colors.indexOf(c);
                    const newIndex = currentIndex &amp;lt; colors.length - 1
                        ? currentIndex + 1 : 0;
                    button.classList.remove(c);
                    button.classList.add(colors[newIndex]);
                }
            });
        });
    };

    document.addEventListener(&apos;mousemove&apos;, (e) =&amp;gt; {
        if (e.movementX === 0 &amp;amp;&amp;amp; e.movementY === 0) {
            queue.clear();
        } else {
            queue.enqueue(changeButtonColors);
        }
    });

    document.addEventListener(&apos;mouseleave&apos;, () =&amp;gt; {
        queue.clear();
    })
});

    class EventQueue {
        constructor(interval) {
            this.queue = [];
            this.interval = interval;
            this.startProcessing();
        }

        enqueue(eventFunction) {
            this.queue.push(eventFunction);
        }

        clear() {
            this.queue = [];
        }

        startProcessing() {
            setInterval(() =&amp;gt; {
                if (this.queue.length &amp;gt; 0) {
                    const eventFunction = this.queue.shift();
                    eventFunction();
                }
            }, this.interval);
        }
    }

&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;You can create interactive experiences with some JavaScript and some CSS. The &lt;code&gt;EventQueue&lt;/code&gt; I wrote is surprisingly
simple yet powerful for my use case, but you can adapt it to your needs. The definition of &lt;code&gt;transition&lt;/code&gt; is also an
excellent tool for keeping visual transitions from being jarring or obnoxious.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and I hope you have a great day. Oh, if you thought this post was cool or helpful, please remember
to share it with friends and colleagues. Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/event-queues-and-buffering-functions-with-javascript</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/event-queues-and-buffering-functions-with-javascript</guid>
        
        <category>javascript,</category>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>Output CSV Results to Console Table in Rust</title>
        <description>&lt;p&gt;‘ve recently been working with Rust and learning about the language and ecosystem by implementing small, typical task
applications. There’s no better way to learn than to jump into it.&lt;/p&gt;

&lt;p&gt;In this post, I’ll cover how I could read data from a CSV file, deserialize the contents into an array of &lt;code&gt;struct&lt;/code&gt;, and
then output that collection into a pretty console table.&lt;/p&gt;

&lt;p&gt;To follow along, I assume you have a working Rust environment. If
not, &lt;a href=&quot;https://www.jetbrains.com/rust/&quot;&gt;I suggest RustRover, which works excellently and provides excellent tooling around the Rust ecosystem.&lt;/a&gt;
Let’s get into it.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;crate-dependencies&quot;&gt;Crate Dependencies&lt;/h2&gt;

&lt;p&gt;I had to research to find the appropriate dependencies required to read a CSV from disk and then deserialize the rows
into a Rust &lt;code&gt;struct&lt;/code&gt;. These are the dependencies I found: &lt;code&gt;csv&lt;/code&gt;, &lt;code&gt;serde&lt;/code&gt;, and &lt;code&gt;lazy_static&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;csv&lt;/code&gt; crate provides helper methods to read CSV files using a readers pattern. We’ll see how this works when we get
to the code sample.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://serde.rs/&quot;&gt;&lt;code&gt;serde&lt;/code&gt; crate&lt;/a&gt; allows me to serialize and deserialize directly into Rust data structures, which
I’ll be doing from the on disk CSV.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;lazy_static&lt;/code&gt; is optional, it will allow us to read and deserialize our rows once for the application’s lifetime.&lt;/p&gt;

&lt;p&gt;There will also be a set of other dependencies that you’ll need to import to get the app working. I also need to
import &lt;a href=&quot;https://ratatui.rs/&quot;&gt;&lt;code&gt;ratatui&lt;/code&gt;&lt;/a&gt; and it’s dependency of &lt;code&gt;crossterm&lt;/code&gt; to work with the terminal.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;[dependencies]
crossterm = &quot;0.27.0&quot;
ratatui = &quot;0.26.1&quot;
csv = &quot;1.3.0&quot;
serde = { version = &quot;1.0.197&quot;, features = [&quot;derive&quot;] }
lazy_static = &quot;1.4.0&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is the complete list of &lt;code&gt;use&lt;/code&gt; statements from the final sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use crossterm::{event:: {self, KeyCode}, ExecutableCommand};
use crossterm::terminal::{enable_raw_mode, EnterAlternateScreen};
use lazy_static::lazy_static;
use ratatui::{prelude::*, widgets::*};
use std::io::{stdout, Result};
use std::process::exit;
use crossterm::event::{Event, KeyEventKind};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ok, we have everything we need to get started writing some code. Let’s start by processing our CSV file. Here is some
sample data.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csv&quot;&gt;name,region,toppings
Margherita,Italy,&quot;Tomatoes, Mozzarella, Basil, Salt, Olive oil&quot;
Hawaiian,Canada,&quot;Tomatoes, Ham, Pineapple, Cheese&quot;
Pepperoni,USA,&quot;Tomatoes, Pepperoni, Cheese&quot;
BBQ Chicken,USA,&quot;BBQ Sauce, Chicken, Onions, Cheese&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;processing-a-csv-row-into-a-struct&quot;&gt;Processing a CSV Row into a Struct&lt;/h2&gt;

&lt;p&gt;While it’s possible to work with CSVs dealing with primitive types, it’s not generally a fun way to work with data.
Instead, we want to deal with logical structures. In the case of this tutorial, we are dealing with &lt;code&gt;Pizza&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;#[derive(Debug, serde::Deserialize)]
pub struct Pizza {
    name: String,
    region: String,
    toppings: String,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The attribute of &lt;code&gt;serde::Deserialize&lt;/code&gt; lets our serialization dependency know that this is something we’d like to fill
with data.&lt;/p&gt;

&lt;p&gt;Now, for the fun part, let’s read the data from disk.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn read_pizzas() -&amp;gt; Vec&amp;lt;Pizza&amp;gt; {
    let mut reader = csv::Reader::from_path(&quot;pizzas.csv&quot;)
        .unwrap_or_else(|err| {
            eprintln!(&quot;Error reading CSV file: {}&quot;, err);
            exit(1);
        });

    reader.deserialize().map(|r| {
        match r {
            Ok(pizza) =&amp;gt; pizza,
            Err(err) =&amp;gt; {
                eprintln!(&quot;Error deserializing pizza: {}&quot;, err);
                exit(1);
            }
        }
    }).collect()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rust expects us to handle the &lt;code&gt;Result&lt;/code&gt; type and all its potential results. In the case of this sample, if the CSV is
mangled, we want to exit the application. As you can see, it’s only two lines of code. The &lt;code&gt;Pizza&lt;/code&gt; type is inferred from
the &lt;code&gt;Vec&amp;lt;Pizza&amp;gt;&lt;/code&gt; return value of our &lt;code&gt;read_pizzas&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;We’ll need to put this information where we can access it once it’s initialized. Here, we’ll use the &lt;code&gt;lazy_static!&lt;/code&gt;
macro to define a global static type.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;lazy_static! {
    static ref PIZZAS: Vec&amp;lt;Pizza&amp;gt; = read_pizzas();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we can access this value using &lt;code&gt;&amp;amp;*PIZZAS&lt;/code&gt; in our code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;let pizzas = &amp;amp;*PIZZAS;
let count = pizzas.len();
println!(&quot;{} total pizzas&quot;, count)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;output-a-pretty-console-table&quot;&gt;Output a Pretty Console Table&lt;/h2&gt;

&lt;p&gt;The next step uses the &lt;code&gt;ratatui&lt;/code&gt; library, but be aware that this library is about building Terminal UIs referred to at
TUIs. The nature of the this library is it relies on a UI loop and every iteration renders the contents. This is a
helpful model, allowing for real-time updates and fascinating use cases.&lt;/p&gt;

&lt;p&gt;To take advantage of &lt;code&gt;ratatui&lt;/code&gt;, we must first update our &lt;code&gt;main&lt;/code&gt; function to have a UI loop.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    stdout().execute(EnterAlternateScreen)?;
    enable_raw_mode()?;
    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
    terminal.clear()?;

    loop {
        terminal.draw(ui)?;
        std::thread::sleep(std::time::Duration::from_millis(10));
        // wait for keys
        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                use KeyCode::*;
                match key.code {
                    Char(&apos;q&apos;) | Esc =&amp;gt; return Ok(()),
                    _ =&amp;gt; {}
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ve also allowed folks to exit the app by hitting &lt;code&gt;q&lt;/code&gt; or &lt;code&gt;Esc&lt;/code&gt;. To reduce the load on the CPU, I’ve also made it so the
thread sleeps every 10 milliseconds, just enough to be responsive but not burn up my cores.&lt;/p&gt;

&lt;p&gt;The only thing left to do is implement the &lt;code&gt;ui&lt;/code&gt; function, but before we do that, we need a helper method to convert
our &lt;code&gt;Pizza&lt;/code&gt; struct, into a &lt;code&gt;Row&lt;/code&gt;. Here we’ll use Rust’s &lt;code&gt;impl&lt;/code&gt; keyword to fill in that functionality.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;impl From&amp;lt;&amp;amp;Pizza&amp;gt; for Row&amp;lt;&apos;_&amp;gt; {
    fn from(p: &amp;amp;Pizza) -&amp;gt; Self {
        Row::new(vec![
            p.name.clone(),
            p.region.clone(),
            p.toppings.clone(),
        ])
            .bottom_margin(1)
            .style(Style::default().fg(Color::White))
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s look at the &lt;code&gt;ui&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn ui(frame: &amp;amp;mut Frame) {
    let pizzas = &amp;amp;*PIZZAS;
    let widths = [
        Constraint::Max(20),
        Constraint::Max(10),
        Constraint::Max(50)
    ];
    let header = Row::new(vec![
        &quot;Name&quot;.to_string(),
        &quot;Region&quot;.to_string(),
        &quot;Toppings&quot;.to_string(),
    ])
        .style(Style::default().fg(Color::White).bg(Color::Blue))
        .bold()
        .bottom_margin(1);

    let table = Table::new(pizzas, widths)
        .header(header)
        .footer(Row::new(vec![format!(&quot;{} Pizzas &quot;, pizzas.len())]))
        .block(Block::new().borders(Borders::ALL).title(&quot;Pizzas&quot;))
        .style(Style::new().blue())
        .widths(widths);

    frame.render_widget(table, frame.size());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty straightforward. Running the application, we’ll see the table rendered in our terminal.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/rust-csv-tables-console/rust-rover-terminal-result.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;Terminal output from rust application in RustRover&quot; loading=&quot;lazy&quot; width=&quot;2278&quot; height=&quot;1378&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s the final codebase in its complete form.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use crossterm::{event::{self, KeyCode}, ExecutableCommand};
use crossterm::terminal::{enable_raw_mode, EnterAlternateScreen};
use lazy_static::lazy_static;
use ratatui::{prelude::*, widgets::*};
use std::io::{stdout, Result};
use std::process::exit;
use crossterm::event::{Event, KeyEventKind, read};

#[derive(Debug, serde::Deserialize)]
pub struct Pizza {
    name: String,
    region: String,
    toppings: String,
}

lazy_static! {
    static ref PIZZAS: Vec&amp;lt;Pizza&amp;gt; = read_pizzas();
}

impl From&amp;lt;&amp;amp;Pizza&amp;gt; for Row&amp;lt;&apos;_&amp;gt; {
    fn from(p: &amp;amp;Pizza) -&amp;gt; Self {
        Row::new(vec![
            p.name.clone(),
            p.region.clone(),
            p.toppings.clone(),
        ])
            .bottom_margin(1)
            .style(Style::default().fg(Color::White))
    }
}

fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    stdout().execute(EnterAlternateScreen)?;
    enable_raw_mode()?;
    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
    terminal.clear()?;

    loop {
        terminal.draw(ui)?;
        std::thread::sleep(std::time::Duration::from_millis(10));
        // wait for keys
        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                use KeyCode::*;
                match key.code {
                    Char(&apos;q&apos;) | Esc =&amp;gt; return Ok(()),
                    _ =&amp;gt; {}
                }
            }
        }
    }
}

fn ui(frame: &amp;amp;mut Frame) {
    let pizzas = &amp;amp;*PIZZAS;
    let widths = [
        Constraint::Max(20),
        Constraint::Max(10),
        Constraint::Max(50)
    ];
    let header = Row::new(vec![
        &quot;Name&quot;.to_string(),
        &quot;Region&quot;.to_string(),
        &quot;Toppings&quot;.to_string(),
    ])
        .style(Style::default().fg(Color::White).bg(Color::Blue))
        .bold()
        .bottom_margin(1);

    let table = Table::new(pizzas, widths)
        .header(header)
        .footer(Row::new(vec![format!(&quot;{} Pizzas &quot;, pizzas.len())]))
        .block(Block::new().borders(Borders::ALL).title(&quot;Pizzas&quot;))
        .style(Style::new().blue())
        .widths(widths);

    frame.render_widget(table, frame.size());
}

fn read_pizzas() -&amp;gt; Vec&amp;lt;Pizza&amp;gt; {
    let mut reader = csv::Reader::from_path(&quot;pizzas.csv&quot;)
        .unwrap_or_else(|err| {
            eprintln!(&quot;Error reading CSV file: {}&quot;, err);
            exit(1);
        });

    reader.deserialize().map(|r| {
        match r {
            Ok(pizza) =&amp;gt; pizza,
            Err(err) =&amp;gt; {
                eprintln!(&quot;Error deserializing pizza: {}&quot;, err);
                exit(1);
            }
        }
    }).collect()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;update-once_cell-instead-of-lazy_static&quot;&gt;Update: Once_cell instead of Lazy_static&lt;/h2&gt;

&lt;p&gt;I typically share my learnings in real-time on Mastodon, and someone mentioned that &lt;code&gt;lazy_static&lt;/code&gt; has been usurped by &lt;code&gt;once_cell&lt;/code&gt;, so I decided to port the code over to use the newer approach. The following lines are converted into the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// 👎 old lazy_static way
lazy_static! {
    static ref PIZZAS: Vec&amp;lt;Pizza&amp;gt; = read_pizzas();
}

// 👍 once_cell Lazy
static PIZZAS: once_cell::sync::Lazy&amp;lt;Vec&amp;lt;Pizza&amp;gt;&amp;gt; =
    once_cell::sync::Lazy::new(|| {
        read_pizzas()
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a much nicer approach in my opinion, and much easier to follow in code. Try out both ways to see which you prefer.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This was a fun little side project, but I learned much from it. For one, I learned more about Rust’s borrow checker and
how to use &lt;code&gt;lazy_static&lt;/code&gt; to create a shared resource in memory. Secondly, I learned how to read CSV files from disk and
deserialize them into a custom &lt;code&gt;struct&lt;/code&gt;. Finally, I learned about &lt;code&gt;ratatui&lt;/code&gt; and building TUIs in Rust.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/output-csv-results-to-console-table-in-rust</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/output-csv-results-to-console-table-in-rust</guid>
        
        <category>rust</category>
        
        
      </item>
    
      <item>
        <title>Responsive Images Crash Course for ASP.NET Core Developers</title>
        <description>&lt;p&gt;Yes, I’m guilty! I’m guilty of ignoring the web platform and all the extraordinary riches waiting for discovery. For all
the lip service the .NET community loves to give towards being performance-minded, it’s a shame we stop at the response
leaving the server. No more fellow reader; it’s time we think beyond the server and think about HTML and, in the case of
this post, images.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to optimize your image delivery using newer HTML features and the differences between
the two approaches. We’ll see how and why you may want to use each approach by weighing the pros and cons. Finally,
we’ll look at cute puppies because who doesn’t love puppies?! Nobody.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-humble-image-tag&quot;&gt;The Humble Image Tag&lt;/h2&gt;

&lt;p&gt;If you’ve ever written HTML, you’ll almost certainly have used the &lt;code&gt;img&lt;/code&gt; tag. Images are an essential element of most
web pages, yet they can also be the downfall of many. Suboptimal images can drag down your &lt;strong&gt;Core Web Vitals&lt;/strong&gt;, the
metrics used to determine how a user may perceive your site’s performance. Let’s look at a plain old image tag you may
typically see in an HTML response.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img alt=&quot;good boy corgi&quot; src=&quot;/img/good-boy@3x.webp&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nothing outrageous, right? Well, this particular image is sub-optimal for many reasons.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This image is &lt;strong&gt;3.1 MB&lt;/strong&gt; and has dimensions of &lt;strong&gt;2000px x 2952px&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;The image tag lacks &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes, so loading the image will cause layout shifts and page redraws&lt;/li&gt;
  &lt;li&gt;We serve one image for all devices, regardless of pixel density or medium. It’s wasteful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see if we can do better.&lt;/p&gt;

&lt;h2 id=&quot;descriptive-responsive-image&quot;&gt;Descriptive Responsive Image&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;img&lt;/code&gt; tag has a few new attributes that can help developers address the above-mentioned issues. Those attributes
are &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;srcset&lt;/code&gt; attribute allows you to define a set of source images the browser should consider when rendering the HTML
to the user. The critical word here is &lt;em&gt;“should”&lt;/em&gt;, as the browser determines the selected image. We’ll see how to steer
the browser in a particular direction, but it will always be up to the browser. First, let’s see an example of an image
with a &lt;code&gt;srcset&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img
    srcset=&quot;/img/good-boy@3x.webp 2000w, /img/good-boy@2x.webp 1000w, /img/good-boy@1x.webp 500w&quot;
    src=&quot;/img/good-boy@1x.webp&quot;
    alt=&quot;a good boy - corgi puppy&quot;
    decoding=&quot;async&quot;
    &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Three images are defined with their width descriptor specified in &lt;code&gt;&amp;lt;number&amp;gt;w&lt;/code&gt; format. The width descriptor tells the
browser what the image’s intrinsic width is in a unit-agnostic way. This is important as some displays have pixel
densities of 1x, 2x, or 3x. We also set the &lt;code&gt;src&lt;/code&gt; tag as a fallback for clients that do not
support &lt;code&gt;srcset&lt;/code&gt;, &lt;a href=&quot;https://caniuse.com/?search=srcset&quot;&gt;although those clients are almost non-existent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s give the browser hints on what to choose when displaying one of our three options. That’s where the &lt;code&gt;sizes&lt;/code&gt;
attribute comes into play.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img  
    srcset=&quot;/img/good-boy@3x.webp 2000w, /img/good-boy@2x.webp 1000w, /img/good-boy@1x.webp 500w&quot;  
    sizes=&quot;(max-width:500px) 500px, (max-width:1000px) 1000px, (max-width:2000px) 2000px&quot;  
    src=&quot;/img/good-boy@1x.webp&quot;  
    alt=&quot;a good boy - corgi puppy&quot;  
    decoding=&quot;async&quot;  
    &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see what the &lt;code&gt;sizes&lt;/code&gt; mean:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When the maximum width of the viewport is 500px, the image will take up 500px in layout.&lt;/li&gt;
  &lt;li&gt;When the maximum width of the viewport is 1000px, the image will take up 1000px in layout.&lt;/li&gt;
  &lt;li&gt;When the maximum width of the viewport is 2000px, the image will take up 2000px in layout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use CSS to define matches in the form of &lt;code&gt;(max-width:500px)&lt;/code&gt;. Additionally, we could use the use case and assume all
images will always be displayed at &lt;code&gt;100vw&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img
    srcset=&quot;/img/good-boy@3x.webp 2000w, /img/good-boy@2x.webp 1000w, /img/good-boy@1x.webp 500w&quot;
    sizes=&quot;100vw&quot;
    src=&quot;/img/good-boy@1x.webp&quot;
    alt=&quot;a good boy - corgi puppy&quot;
    decoding=&quot;async&quot;
    &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, it’s important to note that the client ultimately decides which option is best given the current state of the
viewport.&lt;/p&gt;

&lt;p&gt;What are the advantages of this approach?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The client knows best, so let it choose for you.&lt;/li&gt;
  &lt;li&gt;Once the largest-size asset is loaded, it will always be used from the cache. Upgrades never any downgrades in
quality.&lt;/li&gt;
  &lt;li&gt;Less HTML than the other option.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What are the disadvantages?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Lack of control and “art direction”&lt;/li&gt;
  &lt;li&gt;Black box of when and why things might be chosen.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s look at the next option, the &lt;code&gt;picture&lt;/code&gt; tag, and see how we may overcome some disadvantages.&lt;/p&gt;

&lt;h2 id=&quot;the-descriptive-approach-to-responsive-images&quot;&gt;The Descriptive Approach to Responsive Images&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;picture&lt;/code&gt; tag allows us to describe what image to serve and when to serve it. This allows us a level of control not
available to folks using the &lt;code&gt;img&lt;/code&gt; tag with &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;. Let’s take a look at an example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;picture&amp;gt;
    &amp;lt;source media=&quot;(max-width: 500px)&quot; width=&quot;500&quot; height=&quot;738&quot; srcset=&quot;/img/sad-boy@1x.webp&quot;&amp;gt;
    &amp;lt;source media=&quot;(max-width: 1000px)&quot; width=&quot;1000&quot; height=&quot;1476&quot; srcset=&quot;/img/sad-boy@2x.webp&quot;&amp;gt;
    &amp;lt;source media=&quot;(min-width: 2000px)&quot; width=&quot;2000&quot; height=&quot;2952&quot; srcset=&quot;/img/sad-boy@3x.webp&quot;&amp;gt;
    &amp;lt;img src=&quot;/img/sad-boy@3x.webp&quot; alt=&quot;a sad boy - French bulldog in a hoodie&quot; loading=&quot;lazy&quot;&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you may notice, it’s more verbose, but we now can choose precisely what image gets displayed and when it gets
displayed.&lt;/p&gt;

&lt;p&gt;This can give us a sense of art direction not available with the previous method. We could display images optimized for
mobile devices or desktops based on media queries. This can help us optimize the size and dimensions of an image like we
couldn’t before.&lt;/p&gt;

&lt;p&gt;Advantages of this approach?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Art Direction - Images change as the viewport changes&lt;/li&gt;
  &lt;li&gt;Flexibility&lt;/li&gt;
  &lt;li&gt;Still delivering the optimal experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages to this approach?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Verbose - lots and lots of HTML&lt;/li&gt;
  &lt;li&gt;Resizes may cause additional network requests for new assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see both of these examples in a demo.&lt;/p&gt;

&lt;h2 id=&quot;responsive-images-demo-time&quot;&gt;Responsive Images Demo Time&lt;/h2&gt;

&lt;p&gt;This video is hosted on Mastodon, so you
can &lt;a href=&quot;https://mastodon.social/@khalidabuhakmeh/111925914430361839&quot;&gt;head to my Mastodon page to see it in action&lt;/a&gt;. You can
also head to
my &lt;a href=&quot;https://github.com/khalidabuhakmeh/ResponsiveImages&quot;&gt;GitHub repository to download the sample ASP.NET Core project&lt;/a&gt;.&lt;/p&gt;

&lt;video width=&quot;100%&quot; controls=&quot;&quot; loop=&quot;&quot; style=&quot;border: 1px solid rgb(210, 0, 104)&quot;&gt;
    &lt;source src=&quot;https://files.mastodon.social/media_attachments/files/111/925/914/148/410/853/original/ab69aa01627a7de7.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
&lt;/video&gt;

&lt;p&gt;As you notice, when I resize the window, the pictures of puppies change (look at the 1x, 2x, and 3x in the corners).&lt;/p&gt;

&lt;p&gt;The Corgi’s &lt;code&gt;1x&lt;/code&gt; image is never displayed, but the French Bulldog’s image behaves more predictably. Very cool, right?
Give it a try by downloading the demo from GitHub.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Responsive images are an excellent feature of HTML, but they require a bit of thought upfront and an understanding of
what you’re attempting to accomplish. The &lt;code&gt;img&lt;/code&gt; tag has &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; and might be an easier path for ASP.NET
Core devs as a starting point, but the &lt;code&gt;picture&lt;/code&gt; tag offers more control and “art direction”. Regardless of your choice,
you’ll deliver an optimized experience to your users.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing these posts with friends and colleagues. Cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 02 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/responsive-images-crash-course-for-aspnet-core-developers</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/responsive-images-crash-course-for-aspnet-core-developers</guid>
        
        <category>html,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How To SSR Web Components In ASP.NET Core using TagHelpers</title>
        <description>&lt;p&gt;Web Components are gaining momentum in the web platform space, and frankly, it’s bittersweet for us ASP.NET Core
developers. On the one hand, you can use Web Components in your current ASP.NET Core applications, as I demonstrated in
a previous post, but it isn’t the best experience it could be. You’ll have flashes of unstyled content, layout shifts,
JavaScript code that blocks the critical rendering path, and you’ll not get the server-side rendering (SSR) goodness
developed exclusively for the JavaScript ecosystem.&lt;/p&gt;

&lt;p&gt;In his
post &lt;a href=&quot;https://www.zachleat.com/web/good-bad-web-components/&quot;&gt;“THE GOOD, THE BAD, THE WEB COMPONENTS”&lt;/a&gt;, &lt;a href=&quot;https://zachleat.com/@zachleat&quot;&gt;Zach Leatherman&lt;/a&gt;
wrote about the ideal way to deliver web components to avoid some of the issues I described. In this blog post, we’ll
see how we can use ASP.NET Core’s Tag Helpers to deliver the best experience to users when using Web Components.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-ideal-web-component-delivery-method&quot;&gt;The ideal Web Component delivery method&lt;/h2&gt;

&lt;p&gt;Web Components are a mix of JavaScript and HTML. Nesting your HTML within a custom element tag is best for delivering a
progressively enhanced and seamless experience. Let’s take a look at building a &lt;code&gt;Counter&lt;/code&gt; component. First, let’s see
what the custom element would look like on your page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;1&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and the corresponding JavaScript would be as follows.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class Counter extends HTMLElement {
    connectedCallback() {
        const button = this.querySelector(&quot;button&quot;);
        button.addEventListener(&quot;click&quot;, () =&amp;gt; {
            button.innerText = (parseInt(button.innerText) + 1).toString();
        });
    }
}

customElements.define(&quot;my-counter&quot;, Counter);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This allows the client to render the &lt;code&gt;button&lt;/code&gt; element and its CSS styles in place before the JavaScript attaches the
event listener. That’s awesome, but this technique breaks down quickly once you want to use the counter multiple times.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;1&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;2&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;3&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is especially painful if the internal HTML is complex with multiple nodes.&lt;/p&gt;

&lt;h2 id=&quot;shadow-dom-and-templates&quot;&gt;Shadow Dom and Templates&lt;/h2&gt;

&lt;p&gt;With Web Components, you can avoid repeating yourself by utilizing the &lt;code&gt;template&lt;/code&gt; element. This template can be used in
JavaScript to clone repeated elements within an instance of a component. Let’s look at the HTML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template id=&quot;my-counter-template&quot;&amp;gt;
    &amp;lt;style&amp;gt;
        button {
            background-color: orange;
            color: black;
            padding: .375rem .75rem;
            border-radius: 0.25rem;
            border:  1px solid transparent;
            line-height: 1.5rem;
            cursor: pointer;
            &amp;amp;:hover {
                /* make color darker */
                filter: brightness(75%);
            }
        }
    &amp;lt;/style&amp;gt;
    &amp;lt;button&amp;gt;
        &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;my-counter&amp;gt;1&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;1&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;2&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;3&amp;lt;/my-counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is great for reducing repetition but comes at the expense of additional front-end processing. Let’s look at the
updated JavaScript that now uses the ShadowDom.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class Counter extends HTMLElement {
    connectedCallback() {
        if (this.dataset.template) {
            const template = document.getElementById(&quot;my-counter-template&quot;);
            const shadowRoot = this.attachShadow({mode: &quot;open&quot;});
            shadowRoot.appendChild(template.content.cloneNode(true));
            const button = shadowRoot.querySelector(&quot;button&quot;);
            button.addEventListener(&quot;click&quot;, () =&amp;gt; {
                console.log(button);
                this.innerText = (parseInt(this.innerText) + 1).toString();
            });
		}
    }
}

customElements.define(&quot;my-counter&quot;, Counter);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can probably tell a few things changed in the JavaScript as well. This is a bit more complex, and we lost the
ability to target the elements in our components with external styles from a CSS framework like Bootstrap.&lt;/p&gt;

&lt;p&gt;What if we could get the benefits of the first implementation with the style of the second? Well, luckily, with ASP.NET
Core, we can!&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-taghelpers-to-the-rescue&quot;&gt;ASP.NET Core TagHelpers to the rescue!&lt;/h2&gt;

&lt;p&gt;TagHelpers can do almost anything to the elements within its content, and I mean anything. Let’s look at how we might
implement a &lt;code&gt;WebComponentOptimizer&lt;/code&gt; tag helper in our ASP.NET Core Razor pages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;web-component-optimizer&amp;gt;
    &amp;lt;template name=&quot;my-counter&quot;&amp;gt;
        &amp;lt;button class=&quot;btn btn-danger&quot;&amp;gt;
            &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
        &amp;lt;/button&amp;gt;
    &amp;lt;/template&amp;gt;

    &amp;lt;my-counter&amp;gt;1&amp;lt;/my-counter&amp;gt;
    &amp;lt;my-counter&amp;gt;2&amp;lt;/my-counter&amp;gt;
    &amp;lt;my-counter&amp;gt;3&amp;lt;/my-counter&amp;gt;
&amp;lt;/web-component-optimizer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we render the page, we will get the following HTML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-danger&quot;&amp;gt;
		1
	&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-danger&quot;&amp;gt;
		2
	&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&amp;lt;my-counter&amp;gt;
	&amp;lt;button class=&quot;btn btn-danger&quot;&amp;gt;
		3
	&amp;lt;/button&amp;gt;
&amp;lt;/my-counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The template is processed from the HTML output, and you get some fast and snappy web components on the initial page
load. That’s awesome, right?!&lt;/p&gt;

&lt;p&gt;Well, here’s the tag helper to help you do that. &lt;strong&gt;Note: this is a proof of concept. Before going to a production
environment, you’ll want to test and adapt this for your needs.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using AngleSharp;
using AngleSharp.Dom;
using AngleSharp.Html;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace WebComponentsWithTagHelpers;

public class WebComponentOptimizer : TagHelper
{
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var children = await output.GetChildContentAsync();
        var parser = new HtmlParser();
        var document = await parser.ParseDocumentAsync(children.GetContent());
        
        // clear the output
        output.Content.Clear();
        output.TagName = &quot;&quot;;

        var template = (IHtmlTemplateElement)document.GetElementsByTagName(&quot;template&quot;)[0];
        var webComponentName = template.GetAttribute(&quot;name&quot;);
        
        if (webComponentName is { })
        {
            var outputBuilder = new StringWriter();
            var formatter = new HtmlMarkupFormatter();
            var webComponents = document.GetElementsByTagName(webComponentName);
            
            foreach (var webComponent in webComponents)
            {
                var clone = template.Content.Clone();
                var slot = clone.FindDescendant&amp;lt;IHtmlSlotElement&amp;gt;()!;

                slot.OuterHtml = webComponent.InnerHtml;
                slot.RemoveFromParent();
                webComponent.InnerHtml = clone.ToHtml(); 
                webComponent.ToHtml(outputBuilder,formatter); ;
            }

            output.Content.SetHtmlContent(outputBuilder.ToString());
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a few neat tag helper tricks here.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Setting the &lt;code&gt;TagName&lt;/code&gt; to an empty string removes the parent tag.&lt;/li&gt;
  &lt;li&gt;AngleSharp is a great way to parse the existing DOM&lt;/li&gt;
  &lt;li&gt;You can use a formatter to optimize the final output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/WebComponentsWithTagHelpers&quot;&gt;If you want to try this for yourself, head to GitHub to see the whole sample.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;stretch-goals-other-web-component-frameworks&quot;&gt;Stretch Goals: Other Web Component Frameworks&lt;/h2&gt;

&lt;p&gt;While not shown here, I’d love someone to use the SSR support in their favorite frontend frameworks to integrate with
Razor views. This could improve the initial user experience while allowing developers to use frameworks like Angular,
Vue, and React. Since &lt;code&gt;ProcessAsync&lt;/code&gt; could call out to an NPM process and retrieve the starting HTML from a library.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Web Components are fantastic, and they have so much potential to make the user experience great for users without long
pauses while the UI gets its act together. On the .NET side, ASP.NET Core could be a great option to boost the web
platform with Razor’s strength. This blog post only begins to scratch the surface of what could be possible. I hope you
consider this when building your following UI in ASP.NET Core as an option for delivering world-class experiences.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-ssr-web-components-in-aspnet-core-using-taghelpers</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-ssr-web-components-in-aspnet-core-using-taghelpers</guid>
        
        <category>html,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Blazor&apos;s CSS isolation ::deep issue and solution</title>
        <description>&lt;p&gt;Lately, I’ve been helping a few developers solve some of their issues around Blazor adoption. While I have mixed
feelings about the technology, my urge to help developers overcome their challenges outweighs my trepidation with the
technology itself.&lt;/p&gt;

&lt;p&gt;Recently, I had a Blazor developer have issues with the &lt;code&gt;::deep&lt;/code&gt;  cascading style sheet (CSS) pseudo-selector and the
style’s inability to cascade styles to child components. If you’re having a similar issue, I have a detailed issue
breakdown and potential solution. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-css-isolation&quot;&gt;What is CSS isolation?&lt;/h2&gt;

&lt;p&gt;Blazor is a component-based framework that takes much inspiration from the JavaScript ecosystem’s React component model.
The model focuses on reusability through encapsulation and manifests in a single-file style that combines Razor markup
and C# logic.&lt;/p&gt;

&lt;p&gt;In a Blazor application, CSS can be scoped to a single component by adding a convention-based filename similar to a
component. For example, if your application contains a &lt;code&gt;Counter.razor&lt;/code&gt; component, any styles defined
in &lt;code&gt;Counter.razor.css&lt;/code&gt; would be scoped to the component definition.&lt;/p&gt;

&lt;p&gt;Blazor scopes CSS by adding a component-unique HTML attribute to the HTML rendered on the client. Take, for example, the
contents of &lt;code&gt;Counter.razor.css&lt;/code&gt;, which I’ve added to a new Blazor application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;h1 {
    color: pink;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The resulting CSS is sent to the client when the Blazor build pipeline processes the file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* /Pages/Counter.razor.rz.scp.css */
h1[b-13zswy4nzk] {
    color: pink;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This CSS rule reads, &lt;em&gt;“any H1 in the current document with an attribute of ‘b-13zswy4nzk’ should have pink-colored
text.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Scoped CSS allows you to target components with styles without the risk of having rules conflict with other rules. But
what if you want to take advantage of the cascading part of CSS?&lt;/p&gt;

&lt;h2 id=&quot;using-the-deep-pseudo-selector&quot;&gt;Using the &lt;code&gt;::deep&lt;/code&gt; pseudo-selector&lt;/h2&gt;

&lt;p&gt;As you saw, Blazor processes component-scoped CSS files and adds them to your application’s Blazor CSS file. This allows
Blazor developers to use additional pseudo-selectors to generate different rules. One such pseudo-selector is
the &lt;code&gt;::deep&lt;/code&gt; selector.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;::deep&lt;/code&gt; pseudo-selector will allow you to target child HTML elements nested within a parent component. Let’s change
the previous CSS rule to use this feature.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;::deep h1 {
	color: pink;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After running the Blazor application, we can see the updated CSS rule.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* /Pages/Counter.razor.rz.scp.css */
[b-13zswy4nzk] h1 {
    color: pink;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This new CSS rule reads, “any H1 element found within an element with the attribute of ‘b-13zswy4nzk’ will have a text
color of pink.”.&lt;/p&gt;

&lt;p&gt;Great! Ship it. What’s the issue?&lt;/p&gt;

&lt;h2 id=&quot;the-blazor-attribute-problem&quot;&gt;The Blazor attribute problem&lt;/h2&gt;

&lt;p&gt;Let’s take a look at the &lt;code&gt;Counter.razor&lt;/code&gt; component and a new &lt;code&gt;Child.razor&lt;/code&gt; component with the previous isolated CSS in
mind. First, the &lt;code&gt;Counter.razor&lt;/code&gt; definition.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/counter&quot;

&amp;lt;PageTitle&amp;gt;Counter&amp;lt;/PageTitle&amp;gt;
&amp;lt;Child/&amp;gt;
&amp;lt;p role=&quot;status&quot;&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;
&amp;lt;button class=&quot;btn btn-primary&quot; @onclick=&quot;IncrementCount&quot;&amp;gt;Click me&amp;lt;/button&amp;gt;

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll note the usage of the &lt;code&gt;Child&lt;/code&gt; component right under the &lt;code&gt;PageTitle&lt;/code&gt; component. Let’s see that implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;h1&amp;gt;Counter&amp;lt;/h1&amp;gt;

@code {
    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given the isolated CSS, we would assume that the &lt;code&gt;H1&lt;/code&gt; element within our child component would become &lt;code&gt;pink&lt;/code&gt;, but that’s
not the case. Let’s look at the rendered HTML to see the issue.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;article class=&quot;content px-4&quot; b-5dhe1ruqj7&amp;gt;
    &amp;lt;h1 tabindex=&quot;-1&quot;&amp;gt;Counter&amp;lt;/h1&amp;gt;
    &amp;lt;p role=&quot;status&quot; b-13zswy4nzk&amp;gt;Current count: 0&amp;lt;/p&amp;gt;
    &amp;lt;button class=&quot;btn btn-primary&quot; b-13zswy4nzk&amp;gt;Click me&amp;lt;/button&amp;gt;
&amp;lt;/article&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Do you see the issue? &lt;strong&gt;Blazor adds the unique attribute to all top-level HTML elements within a component. This creates
a mismatch between markup and the CSS rule.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the rendered HTML, the &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;button&lt;/code&gt; elements get the attribute &lt;code&gt;b-13zswy4nzk&lt;/code&gt;, but our &lt;code&gt;Child&lt;/code&gt; component is used
within the &lt;code&gt;Counter&lt;/code&gt; component but before the any HTML element. Worse, there are no encapsulating HTML elements.&lt;/p&gt;

&lt;h2 id=&quot;the-fix-to-deep--styles&quot;&gt;The fix to ::deep  styles&lt;/h2&gt;

&lt;p&gt;So you’ve read this far and want to know the solution to the problem. It’s relatively straightforward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If your usage of the &lt;code&gt;::deep&lt;/code&gt; pseudo-selector is not working, you need to add a wrapping HTML element within your
parent component that is a parent to all usages of child components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s fix our &lt;code&gt;Counter.razor&lt;/code&gt; markup with a straightforward change.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/counter&quot;

&amp;lt;div&amp;gt;
	&amp;lt;PageTitle&amp;gt;Counter&amp;lt;/PageTitle&amp;gt;
	&amp;lt;Child/&amp;gt;
	&amp;lt;p role=&quot;status&quot;&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;
	&amp;lt;button class=&quot;btn btn-primary&quot; @onclick=&quot;IncrementCount&quot;&amp;gt;Click me&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we re-run our application, we can see that the unique attribute is now on the first HTML element along with the
previous elements of &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;button&lt;/code&gt; and our CSS rule now targets nested HTML elements correctly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div b-13zswy4nzk&amp;gt;
    &amp;lt;h1 tabindex=&quot;-1&quot;&amp;gt;Counter&amp;lt;/h1&amp;gt;
    &amp;lt;p role=&quot;status&quot; b-13zswy4nzk&amp;gt;Current count: 0&amp;lt;/p&amp;gt;
    &amp;lt;button class=&quot;btn btn-primary&quot; b-13zswy4nzk&amp;gt;Click me&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This fixes the issue, but depending on the CSS framework library you’re using, a parent &lt;code&gt;div&lt;/code&gt; HTML element may break
your layout. Experiment with different HTML tags to see which ones you can use as wrappers while not breaking global CSS
rules.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;CSS Isolation is a technique for continuing the philosophy of encapsulating as much within the bounds of a component,
but there are times where you want the cascade to do its job. To get the &lt;code&gt;::deep&lt;/code&gt; pseudo-selector element working
properly, all your Blazor components should have a single-wrapping HTML element as the root element. If your Blazor
components do not have a parent element, you’ll get CSS rules that don’t ultimately match your HTML markup.&lt;/p&gt;

&lt;p&gt;Hope this post helped, and as always, thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 19 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/blazors-css-isolation-deep-issue-and-solution</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/blazors-css-isolation-deep-issue-and-solution</guid>
        
        <category>blazor,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How to use No-Class Frameworks to Move Fast in Style</title>
        <description>&lt;p&gt;Software development can be a struggle between form and function. With many developers, function takes the driver’s
seat, while the aesthetics of an application are lucky to have a seat in the vehicle. Rational minds might say, “Well,
what does it matter how it looks? As long as it works right?” but great design isn’t always rational; it’s emotional.&lt;/p&gt;

&lt;p&gt;Many developers look to supplement their design deficits with style libraries like Bootstrap, Tailwind CSS, and Bulma to
evoke strong user emotions. These are great initial options, but they typically are temporary substitutes for greater
ambitions of bespoke design systems. Style libraries can also stand in the way of evolving a UI to meet user needs since
they heavily rely on library-specific HTML, JavaScript, and CSS classes. Removing these dependencies is unlikely once
they find their way into your codebase.&lt;/p&gt;

&lt;p&gt;To my surprise, there have been a few attempts to give developers a strong design starting point while leveraging HTML’s
existing semantics and foundational elements. This movement is known as &lt;strong&gt;“No-class Frameworks&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;In general, No-class frameworks force developers to write semantically appropriate HTML while limiting the need for CSS
classes in the markup. The libraries do their best to use the HTML markup to style around standard practices.&lt;/p&gt;

&lt;p&gt;This post will look at MVP.CSS and some examples of styled HTML elements. Then, we’ll discuss the advantages and
disadvantages of using a no-class framework in your application.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;mvpcss---a-no-class-framework&quot;&gt;MVP.CSS - a No-class framework&lt;/h2&gt;

&lt;p&gt;As the name suggests, &lt;a href=&quot;https://andybrewer.github.io/mvp/&quot;&gt;MVP.CSS is a style library&lt;/a&gt; designed to help developers build
web pages for their minimal viable
product (MVP) projects. The MVP is a common practice in tech circles to build a functional product while only including
the bare essentials feature set. As the name suggests, the library’s aesthetics are muted and restrained but better than
what you’d get if you used nothing.&lt;/p&gt;

&lt;p&gt;To get started with MVP.CSS, add a single no-build stylesheet to the page’s header.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://unpkg.com/mvp.css&quot;&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://andybrewer.github.io/mvp/&quot;&gt;In a feature grid on the site&lt;/a&gt;, MVP.CSS boasts that it is mobile-friendly, works out
of the box, easily customizable, and only operates on semantic HTML.&lt;/p&gt;

&lt;p&gt;Let’s see what a styled table’s HTML looks like.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/no-class-style-frameworks/mvp-css-table-style.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/no-class-style-frameworks/mvp-css-table-style.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/no-class-style-frameworks/mvp-css-table-style.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_682/https://khalidabuhakmeh.com/assets/images/posts/no-class-style-frameworks/mvp-css-table-style.png 682w&quot; sizes=&quot;100vw&quot; alt=&quot;mvp.css styled HTML table&quot; loading=&quot;lazy&quot; width=&quot;682&quot; height=&quot;300&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;table&amp;gt;
    &amp;lt;thead&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Col A&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Col B&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Col C&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Row 1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell A1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell B1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell C1&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Row 2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell A2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell B2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Cell C2&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This approach applies to many common HTML elements, including headings, forms, navigation, quotes, and lists.&lt;/p&gt;

&lt;p&gt;While the initial white and blue color scheme might suit most situations, MVP.CSS allows library consumers to modify the
visual rendering with global CSS variables. After loading the library, you can control background, primary, and
secondary colors and font choices by modifying the following rule in a custom stylesheet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;:root {
    --active-brightness: 0.85;
    --border-radius: 5px;
    --box-shadow: 2px 2px 10px;
    --color-accent: #118bee15;
    --color-bg: #fff;
    --color-bg-secondary: #e9e9e9;
    --color-link: #118bee;
    --color-secondary: #920de9;
    --color-secondary-accent: #920de90b;
    --color-shadow: #f4f4f4;
    --color-table: #118bee;
    --color-text: #000;
    --color-text-secondary: #999;
    --font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;
    --hover-brightness: 1.2;
    --justify-important: center;
    --justify-normal: left;
    --line-height: 1.5;
    --width-card: 285px;
    --width-card-medium: 460px;
    --width-card-wide: 800px;
    --width-content: 1080px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;the-advantages-of-no-class-frameworks&quot;&gt;The Advantages of No-Class Frameworks&lt;/h2&gt;

&lt;p&gt;There are several advantages to using a No-Class framework, some obvious and others less so.&lt;/p&gt;

&lt;h3 id=&quot;less-stuff&quot;&gt;Less Stuff&lt;/h3&gt;

&lt;p&gt;Semantic HTML leads to smaller payloads for the client, and the parsing of CSS and HTML required to create the CSSDOM
and DOM is significantly less work. That leads to consistently faster pages and better user experiences.&lt;/p&gt;

&lt;h3 id=&quot;simplified-markup&quot;&gt;Simplified Markup&lt;/h3&gt;

&lt;p&gt;If you’ve worked with any CSS framework, you’ve likely spent significant time in the documentation. With No-Class
frameworks, your HTML will render as you expect without additional classes or markups.&lt;/p&gt;

&lt;h3 id=&quot;no-build-tools&quot;&gt;No Build Tools&lt;/h3&gt;

&lt;p&gt;In most cases, since there is a limited number of HTML elements, most No-class frameworks don’t require any build tools.
The build tools in the JavaScript ecosystem can be a frustrating experience, especially for developers working in other
ecosystems.&lt;/p&gt;

&lt;h3 id=&quot;simple-exit-strategy&quot;&gt;Simple Exit Strategy&lt;/h3&gt;

&lt;p&gt;When you’ve decided you need more from your UI, you have a great starting point to style existing HTML without the
tedious work of extracting the previous styles and framework-dependent HTML.&lt;/p&gt;

&lt;h3 id=&quot;embrace-the-css-platform&quot;&gt;Embrace the CSS Platform&lt;/h3&gt;

&lt;p&gt;Other approaches may be seen as fighting against the HTML and CSS platform by jamming design-oriented classes into the
document. No-Class tries to stay closer to the platform, letting you take advantage of modern CSS rather than treating
CSS as an intermediate language.&lt;/p&gt;

&lt;h2 id=&quot;disadvantages-of-no-class-frameworks&quot;&gt;Disadvantages of No-Class Frameworks&lt;/h2&gt;

&lt;p&gt;No-class frameworks aren’t all rainbows and unicorns, as they have definite drawbacks. We’ll point these out in this
section.&lt;/p&gt;

&lt;h3 id=&quot;limited-html-components&quot;&gt;Limited HTML Components&lt;/h3&gt;

&lt;p&gt;While an extensive list of HTML components is in the HTML specification, they are limited. If you’re building a unique
web experience, you’re likely to hit this limitation sooner than later.&lt;/p&gt;

&lt;h3 id=&quot;minimal-layout-options&quot;&gt;Minimal Layout Options&lt;/h3&gt;

&lt;p&gt;The ethos of these frameworks is around common style patterns, which don’t offer many visual options. The lack of bells
and whistles can make pages feel repetitive. CSS grids and Flexbox can provide options that work well with semantic
HTML.&lt;/p&gt;

&lt;h3 id=&quot;bring-your-style&quot;&gt;Bring Your Style&lt;/h3&gt;

&lt;p&gt;You’re out of luck if you seek guidance around a cohesive color palette and iconography. The missing style guidance can
feel like being back at square one for many folks who think a style library aims to make these kinds of decisions for
them.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This post was inspired by a &lt;a href=&quot;https://css-tricks.com/no-class-css-frameworks/&quot;&gt;2020 blog post by Chris Coyier&lt;/a&gt;, and while
the blog post is a few years old, the message of leaning on the web platform has never been more critical. With No-class
frameworks, developers can ship lightweight user experiences that work for a wider audience without the burden of
heavier CSS frameworks.&lt;/p&gt;

&lt;p&gt;The advancements in HTML and CSS have never made it more possible to build familiar experiences without the burden of
past limitations. If you’re starting a new project, I recommend starting with a No-class approach and seeing how far you
get. Even if you reach for another library, you’ll have begun in a much simpler place and better appreciate how far you
can get with so little.&lt;/p&gt;
</description>
        <pubDate>Tue, 12 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-no-class-frameworks-to-move-fast-in-style</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-no-class-frameworks-to-move-fast-in-style</guid>
        
        <category>css,</category>
        
        <category>style</category>
        
        
      </item>
    
      <item>
        <title>How to Integrate HTMX and Shoelace Web Components</title>
        <description>&lt;p&gt;In my last post, &lt;a href=&quot;/shoelace-web-components-with-aspnet-core&quot;&gt;Shoelace Web Components with ASP.NET Core&lt;/a&gt;, I showed ASP.NET Core developers how to
integrate the web components of Shoelace into an existing web application. It’s incredible, and you should check it out.
If you’ve read this blog any time, you might have read a post or two about &lt;a href=&quot;https://htmx.org&quot;&gt;HTMX&lt;/a&gt;, a library for
building dynamic and maintainable web experiences; I love it.&lt;/p&gt;

&lt;p&gt;While the two libraries can work together, there’s an issue you need to work around to get the advantages of both. In
this post, we’ll discuss the issues with using Shoelace with HTMX and how to get it working again with your ASP.NET Core
applications. If you’re using any other technology stack (Django, Spring, or Next.js), don’t worry; the solution here
will work for you, too.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;update-in-htmx-20-and-shadow-dom-support&quot;&gt;Update in HTMX 2.0 and Shadow DOM support&lt;/h2&gt;

&lt;p&gt;For folks using &lt;a href=&quot;https://htmx.org&quot;&gt;HTMX 2.0&lt;/a&gt;, the HTMX library has since resolved this issue and you’re no longer required to perform the steps in this blog post. Users of HTMX pre-2.0 will still need the following blog post, but I would recommend upgrading to the latest version. The biggest changes in HTMX include moving all extensions out of the core library and making them opt-in.&lt;/p&gt;

&lt;p&gt;I’ve confirmed the expected behavior &lt;a href=&quot;https://github.com/khalidabuhakmeh/Shoelace-AspNetCore/tree/shoelace-htmx2&quot;&gt;in a branch on my GitHub Repository&lt;/a&gt;. Cheers. 🍻&lt;/p&gt;

&lt;h2 id=&quot;shoelace-the-shadow-dom-and-htmx&quot;&gt;Shoelace, the Shadow DOM, and HTMX&lt;/h2&gt;

&lt;p&gt;Shoelace is a web component library that &lt;em&gt;encapsulates&lt;/em&gt; all functionality in a user-friendly HTML tag. Let’s take a look
at the most common element, the &lt;a href=&quot;https://shoelace.style/components/button&quot;&gt;&lt;strong&gt;Button&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After installing the Shoelace scripts, adding the &lt;code&gt;sl-button&lt;/code&gt; element in HTML markup is straightforward.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;sl-button&amp;gt;Button&amp;lt;/sl-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The abstraction works out nicely from a developer and user perspective, as these elements “just work” with HTML (as you
might have read in the post mentioned earlier). Looking at how a client renders this element shows some of the
implementation details.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;sl-button variant=&quot;default&quot; size=&quot;medium&quot; data-optional=&quot;&quot; data-valid=&quot;&quot;&amp;gt;
    #shadow-root (open)
    &amp;lt;button part=&quot;base&quot; class=&quot; button button--default button--medium button--standard button--has-label &quot; type=&quot;button&quot;
            title=&quot;&quot; name=&quot;&quot; value=&quot;&quot; role=&quot;button&quot; aria-disabled=&quot;false&quot; tabindex=&quot;0&quot;&amp;gt;
        &amp;lt;slot name=&quot;prefix&quot; part=&quot;prefix&quot; class=&quot;button__prefix&quot;&amp;gt;&amp;lt;/slot&amp;gt;
        &amp;lt;slot part=&quot;label&quot; class=&quot;button__label&quot;&amp;gt;&amp;lt;/slot&amp;gt;
        &amp;lt;slot name=&quot;suffix&quot; part=&quot;suffix&quot; class=&quot;button__suffix&quot;&amp;gt;&amp;lt;/slot&amp;gt;
        &amp;lt;!--?lit$16265820754$--&amp;gt;
        &amp;lt;!--?lit$16265820754$--&amp;gt;
    &amp;lt;/button&amp;gt;
    Button
&amp;lt;/sl-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Shoelace uses the &lt;a href=&quot;https://lit.dev&quot;&gt;Lit library&lt;/a&gt; to build components utilizing the Shadow DOM. These elements exist
virtually in the DOM and are part of the page but may or may not be accessible based on the implementation.&lt;/p&gt;

&lt;p&gt;As you likely guessed, HTMX doesn’t look at the Shadow DOM of custom web components to find common elements such
as &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, or &lt;code&gt;select&lt;/code&gt;. This can be a problem for folks using HTMX to hijack &lt;code&gt;form&lt;/code&gt; elements or adding &lt;code&gt;hx-&lt;/code&gt;
attributes to shoelace components. These custom components aren’t added to the ultimate request that HTMX builds.&lt;/p&gt;

&lt;p&gt;Don’t worry; there’s an easy fix.&lt;/p&gt;

&lt;h2 id=&quot;htmx-events-to-the-rescue&quot;&gt;HTMX Events To The Rescue&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://htmx.org/docs/#events&quot;&gt;HTMX has many events&lt;/a&gt; that allow you to intercept context at any point in the process.
For our use case, we want to intercept all outgoing requests and determine if our &lt;code&gt;target&lt;/code&gt; element and any of its
children contain Shoelace components.&lt;/p&gt;

&lt;p&gt;Luckily for us, Shoelace components follow a typical pattern of having &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; attributes. We can assume that
any element with a &lt;code&gt;name&lt;/code&gt; attribute is expected to be transmitted in a request.&lt;/p&gt;

&lt;p&gt;Let’s hook into the &lt;code&gt;htmx:beforeRequest&lt;/code&gt;. Add the following code into any script file that loads after HTMX and Shoelace
libraries.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;document.body.addEventListener(&apos;htmx:beforeRequest&apos;, evt =&amp;gt; {
    const elements = [
        evt.target,
        ...evt.target.querySelectorAll(&apos;*&apos;)
    ];

    for (const el of elements) {
        const {tagName, name, value, disabled, checked} = el;

        // ignore inputs that aren&apos;t from shoelace
        if (!tagName.startsWith(&quot;SL-&quot;)) continue;
        // all inputs can be disabled
        if (disabled) continue;
        // the name is required
        if (name === undefined || name === &quot;&quot;) continue;
        if (value === undefined) continue;

        // a checkable element
        if (checked !== undefined) {
            if (checked) {
                evt.detail.requestConfig.parameters[name] = value;
            }
        } else {
            // it is a simple element
            evt.detail.requestConfig.parameters[name] = value;
        }
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that form values can have duplicate names within a form collection. I don’t commonly duplicate names, but it might
be a typical pattern for arrays in other technology stacks. If so, you may need to alter the code above to suit your
needs.&lt;/p&gt;

&lt;p&gt;As an additional note, there may be some components you need to account for in your server code. For
example, &lt;code&gt;sl-select&lt;/code&gt; component works with arrays.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The current value of the select, submitted as a name/value pair with form data. When&lt;code&gt;multiple&lt;/code&gt;is enabled, the value
attribute will be a space-delimited list of values based on the options selected, and the value property will be an
array. &lt;strong&gt;For this reason, values must not contain spaces.&lt;/strong&gt;
–&lt;a href=&quot;https://shoelace.style/components/select&quot;&gt;Shoelace Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So far, in my testing, this code works with most of the shoelace elements in the official documentation. That said,
please test and modify the code according to your needs.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It’s always fun when things work together, but it’s not always the case. Luckily, both HTMX and Shoelace offer great
APIs that allow you to smooth out some of these issues. Please try these two libraries in your ASP.NET Core applications
and let me know how it goes.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading the posts, and I hope I helped you get on your way to a productive day. Cheers.&lt;/p&gt;

&lt;p&gt;*&lt;a href=&quot;https://mariohamann.com/livewire-web-components-attributes&quot;&gt;Special thanks to Mario Hamann and his excellent post integrating Web Components and Livewire.&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 05 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-integrate-htmx-and-shoelace-web-components</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-integrate-htmx-and-shoelace-web-components</guid>
        
        <category>htmx,</category>
        
        <category>javascript,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Shoelace Web Components with ASP.NET Core</title>
        <description>&lt;p&gt;Web Components are a powerful way to add UX to your web applications while using the web platform. That makes them ideal
as they can be used in various ecosystems with little or no changes. They also require no build pipelines as they are
supported natively in most clients. This is in stark contrast to approaches like React or Blazor.&lt;/p&gt;

&lt;p&gt;A mature web component library like &lt;a href=&quot;https://shoelace.style&quot;&gt;Shoelace&lt;/a&gt; allows you to share common UI components with
teams working on different technology stacks. This can create a consistent user experience regardless of the server
technology used to render the pages. Take advantage of server-side rendering strengths without heavy SPA libraries or
confusing build pipelines.&lt;/p&gt;

&lt;p&gt;In this repository, you will find a sample using Shoelace components that work with ASP.NET Core Razor Pages and
TagHelpers.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-a-web-component&quot;&gt;What is a Web Component?&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_Components&quot;&gt;web component&lt;/a&gt; is a reusable component written to take advantage of the
standard component model built into some of the most popular web clients, such as Chrome, Firefox, and Safari. The
component model includes three sets of technologies, and a web component can take advantage of one or all of them:
Custom Elements, Shadow DOM, and HTML Templates.&lt;/p&gt;

&lt;p&gt;The goal of web components is to reduce unnecessary overhead by building commonly run tasks into the web platform
itself. This helps increase interoperability across UI frameworks and improve the performance of many frontend
experiences.&lt;/p&gt;

&lt;h2 id=&quot;what-is-shoelace&quot;&gt;What is Shoelace?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://shoelace.style&quot;&gt;Shoelace is a “forward-thinking library for web components.”&lt;/a&gt; The library attempts to create
reusable UI elements that
you can utilize as-is or within other existing UI frameworks, such as React, Vue, or Angular. Some of these components
include common patterns such as input elements, badges, buttons, alerts, and so many more. Shoelace also provides
consumers with a stylistic starting point, but allows for all component details to be altered.&lt;/p&gt;

&lt;p&gt;To get started with Shoelace is straightforward, as all you need is to register the library in your web pages &lt;code&gt;head&lt;/code&gt;
tag.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.12.0/cdn/themes/light.css&quot;/&amp;gt;
&amp;lt;script type=&quot;module&quot;
        src=&quot;https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.12.0/cdn/shoelace-autoloader.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also choose to selectively bundle Shoelace using a JavaScript build pipeline, but this step is optional.&lt;/p&gt;

&lt;h2 id=&quot;adding-shoelace-to-aspnet-core&quot;&gt;Adding Shoelace to ASP.NET Core&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/Shoelace-AspNetCore&quot;&gt;Check out the working sample on my GitHub repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are not that many steps required to add Shoelace to an existing ASP.NET Core application. Shoelace also integrates
well with existing UI libraries such as Bootstrap.&lt;/p&gt;

&lt;p&gt;In a new ASP.NET Core project, replace the top of the &lt;code&gt;_Layout.cshtml&lt;/code&gt; file with the following markup.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@{
    const string shoelaceStylesheet = &quot;https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.12.0/cdn/themes/light.css&quot;;
    const string shoelaceJavaScript = &quot;https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.12.0/cdn/shoelace-autoloader.js&quot;;
}

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;/&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&amp;gt;
    &amp;lt;title&amp;gt;@ViewData[&quot;Title&quot;] - SweetKicks&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/lib/bootstrap/dist/css/bootstrap.min.css&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/css/site.css&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/SweetKicks.styles.css&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;@shoelaceStylesheet&quot; /&amp;gt;
    &amp;lt;script type=&quot;module&quot; src=&quot;@shoelaceJavaScript&quot;&amp;gt;&amp;lt;/script&amp;gt;
    @await RenderSectionAsync(&quot;headScripts&quot;, required: false)
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want the URLs inline, you will need to escape the &lt;code&gt;@&lt;/code&gt; symbols with &lt;code&gt;@@&lt;/code&gt;. In this case, I thought it would be
easier to read if I moved the URLs to the beginning of the file.&lt;/p&gt;

&lt;p&gt;I have added an extra section of &lt;code&gt;headScripts&lt;/code&gt;, which we will use later.&lt;/p&gt;

&lt;p&gt;The most essential element of this code snippet is the script reference to &lt;code&gt;shoelace-autoloader.js&lt;/code&gt;, which scans the
page for shoelace components and then auto-wires those components into the known set of custom elements. Without this,
elements would not render and be visible to users.&lt;/p&gt;

&lt;p&gt;Let’s add some code to our &lt;code&gt;Index.cshtml.cs&lt;/code&gt; to set up for the eventual use of Shoelace components.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace SweetKicks.Pages;

public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    [TempData]
    public string? Name { get; set; }
    
    public void OnGet()
    {
    }

    public RedirectToPageResult OnPost([FromForm] string name)
    { 
        logger.LogInformation(&quot;Name is {Name}&quot;, name);
        Name = name;
        return RedirectToPage();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before we get to using the Shoelace components, we need to let ASP.NET Core know about the &lt;code&gt;sl-input&lt;/code&gt; component we’ll be
using so we can take advantage of tag helpers. Place the following file anywhere in the project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace SweetKicks.TagHelpers;

[UsedImplicitly]
[HtmlTargetElement(&quot;sl-input&quot;, Attributes = &quot;asp-for&quot;, TagStructure = TagStructure.WithoutEndTag)]
public class ShoelaceInputTagHelper(IHtmlGenerator generator) 
    : InputTagHelper(generator);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, be sure to register the new tag helper in &lt;code&gt;_ViewImports.cshtml&lt;/code&gt; making sure to adjust the namespace according to
your needs.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@using SweetKicks
@namespace SweetKicks.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, SweetKicks
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s use some Shoelace components. In &lt;code&gt;Index.cshtml&lt;/code&gt;, we can replace the following HTML with the following markup.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page
@model IndexModel
@{
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;
}

&amp;lt;div&amp;gt;
    @if (Model.Name is not null)
    {
        &amp;lt;sl-alert open&amp;gt;
            &amp;lt;sl-icon slot=&quot;icon&quot; name=&quot;info-circle&quot;&amp;gt;&amp;lt;/sl-icon&amp;gt;
            Your name is @Model.Name
        &amp;lt;/sl-alert&amp;gt;
    }

    &amp;lt;form method=&quot;post&quot; asp-page=&quot;Index&quot; class=&quot;my-3&quot;&amp;gt;
        &amp;lt;sl-input label=&quot;What is your name?&quot;
                  type=&quot;text&quot;
                  asp-for=&quot;Name&quot;
                  help-text=&quot;ex. Alex Murphy&quot;
                  required
                  autofocus&amp;gt;
        &amp;lt;/sl-input&amp;gt;
        &amp;lt;sl-button class=&quot;mt-2&quot; variant=&quot;primary&quot; type=&quot;submit&quot;&amp;gt;Submit&amp;lt;/sl-button&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running the application now shows our input element. Submitting the form will also show the alert notification.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/khalidabuhakmeh/Shoelace-AspNetCore/raw/main/shoelace-aspnetcore-running-sample.png&quot; alt=&quot;shoelace components in asp.net core&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you take a look at the markup again, you’ll notice that a single &lt;code&gt;sl-input&lt;/code&gt; got us a user experience that includes a
label, a placeholder, and input. Additionally, with our &lt;code&gt;ShoelaceInputTagHelper&lt;/code&gt; class, we now have ASP.NET Core support
for web components. Not bad at all.&lt;/p&gt;

&lt;h2 id=&quot;flash-of-content-fixes&quot;&gt;Flash Of Content Fixes&lt;/h2&gt;

&lt;p&gt;Eagle-eyed developers may have noticed a flash of undefined content as the components were rendered. There are several
fixes to this, with
them &lt;a href=&quot;https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/&quot;&gt;coming from this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first and simplest fix is to use a CSS style in the &lt;code&gt;site.css&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;:not(:defined) {
    visibility: hidden;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This won’t render any undefined elements, including any sub content. This is OK, but can still be jarring.&lt;/p&gt;

&lt;p&gt;The second fix is to add the following CSS to the &lt;code&gt;site.css&lt;/code&gt; stylesheet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;body {
    margin-bottom: 60px;
    opacity: 0;
}

body.ready {
    opacity: 1;
    transition: .25s opacity;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then to modify either the &lt;code&gt;_Layout.cshtml&lt;/code&gt; or &lt;code&gt;Index.cshtml&lt;/code&gt; file with the following JavaScript snippet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;
    /* note: this will block rendering if forget
       using a mentioned custom component. 
     ex. sl-not-a-real-component */
    await Promise.allSettled([
        customElements.whenDefined(&apos;sl-input&apos;),
        customElements.whenDefined(&apos;sl-button&apos;),
    ]);

    document.body.classList.add(&apos;ready&apos;);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You may also do this on a per-page basis using predefined sections.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@section headScripts
{
    &amp;lt;script type=&quot;module&quot;&amp;gt;
          /* note: this will block rendering if forget
             using a mentioned custom component. 
           ex. sl-not-a-real-component */
          await Promise.allSettled([
            customElements.whenDefined(&apos;sl-input&apos;),
            customElements.whenDefined(&apos;sl-button&apos;),        
          ]);
              
          document.body.classList.add(&apos;ready&apos;);
    &amp;lt;/script&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As noted in the comment, this approach will block the page rendering until the client is finished registering the
mentioned components. After they are done loading, the page will transition from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; opacity. This provides a
nice experience, but has the downside of needing to track all components that are used on a page.&lt;/p&gt;

&lt;p&gt;I personally prefer the first approach as you’d less likely break the entire page by accidentally removing an element
that you had previously registered.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Web Components are awesome and are the future of web development. There are still some caveats, but in my opinion, they
can help reduce vendor lock-in and ultimately
provide more value to teams who may be doing polyglot development. There’s also a world of unexplored possibilities with
web components depending on your approach. With Shoelace, all components encapsulate functionality, and that’s great for
feature reuse. There’s another approach of progressive enhancement components that can take existing HTML and enrich it
with additional client-side features. I highly recommend you check out the other components in
the &lt;a href=&quot;https://shoelace.style&quot;&gt;Shoelace&lt;/a&gt; component library.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts.&lt;/p&gt;
</description>
        <pubDate>Tue, 27 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/shoelace-web-components-with-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/shoelace-web-components-with-aspnet-core</guid>
        
        <category>html,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How to Map SQL Results To Any Object Using Entity Framework Core 8</title>
        <description>&lt;p&gt;Entity Framework Core 8 packs a punch, aiming for the undisputed title of “most powerful Object-Relational Mapper (ORM)”
in the .NET space. Many folks in our community are typically divided about using ORMs, with many preferring Micro-ORMs.
A Micro-ORM has basic mapping functionality from SQL results but lacks object-tracking features that make ORMs what they
are.&lt;/p&gt;

&lt;p&gt;What Micro-ORMs lack in object-tracking, they make up for in simplicity and functionality. The most popular library is
Dapper, which allows folks to write SQL, execute the query, and map the results to any .NET Object. Well, with Entity
Framework Core 8, you can have Dapper-like functionality with the strengths of EF Core.&lt;/p&gt;

&lt;p&gt;This post will be short, but for most folks, this is a public service announcement to improve performance and tune
existing code paths. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;whats-this-about-mapping-any-object&quot;&gt;What’s this about Mapping Any Object?&lt;/h2&gt;

&lt;p&gt;Before the EF Core 8 release, all entities that were to be queried from a &lt;code&gt;DbContext&lt;/code&gt; had to be registered within the
implementation. These types are typically referenced as a &lt;code&gt;DbSet&amp;lt;T&amp;gt;&lt;/code&gt;. Anyone who’s worked with a database understands
that SQL allows us to create &lt;em&gt;any&lt;/em&gt; result we like, even though those entities might not directly exist in our schema.
This disadvantaged EF Core compared to Dapper, which lets you craft any SQL statements you want and map them to C#
objects.&lt;/p&gt;

&lt;p&gt;In EF Core 8, you can now use &lt;code&gt;SqlQuery&amp;lt;T&amp;gt;&lt;/code&gt; to pass in any SQL statement and map the results to a C# object.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var result = await db
    .Database
    .SqlQuery&amp;lt;NamedResult&amp;gt;($&quot;Select Id, Name from Customers&quot;)
    .FirstOrDefaultAsync();

Console.WriteLine($&quot;NamedResult: {result}&quot;);

record NamedResult(int Id, string Name);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome! As a bonus, you can apply additional LINQ methods to your existing SQL statement.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var result = await db
    .Database
    .SqlQuery&amp;lt;NamedResult&amp;gt;($&quot;Select Id, Name from Customers&quot;)
    .Where(c =&amp;gt; c.Id == 1)
    .FirstOrDefaultAsync();

Console.WriteLine($&quot;NamedResult: {result}&quot;);

record NamedResult(int Id, string Name);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The EF Core generates an SQL statement that uses a nested select to keep your original query intact while adding
additional filtering.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT &quot;n&quot;.&quot;Id&quot;, &quot;n&quot;.&quot;Name&quot;
FROM (
  Select Id, Name from Customers
) AS &quot;n&quot;
WHERE &quot;n&quot;.&quot;Id&quot; = 1
LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you have it. I hope you enjoyed this short post. I’m glad to see this feature as part of EF Core 8 finally. It’s
been a long time in the making, and thanks to the EF Core team for making it happen.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-map-sql-results-to-any-object-using-entity-framework-core-8</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-map-sql-results-to-any-object-using-entity-framework-core-8</guid>
        
        <category>dotnet,</category>
        
        <category>entity-framework</category>
        
        
      </item>
    
      <item>
        <title>Increase Performance with Complex Types in Entity Framework Core 8</title>
        <description>&lt;p&gt;With the release of .NET 8, we also see the release of Entity Framework Core 8 and a bounty of new features. One of my
favorite new features is Complex Types. When data modeling with Entity Framework Core, we may unnecessarily add tables
to our database schema because “that’s just how database modeling works”. This can lead to table sprawl, decreased
insert performance, and increased query times.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to use &lt;strong&gt;Complex Types&lt;/strong&gt; in Entity Framework Core 8 to reduce the number of tables in
our schema, simplify inserts, and increase query performance.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-are-complex-types&quot;&gt;What are Complex Types?&lt;/h2&gt;

&lt;p&gt;Entity Framework Core has long had the concept of “owned types”, which are properties dependent on their parent object.
Depending on your data model, these pieces of information only make sense within the context of additional data. For
example, in a hypothetical domain, a physical address may only make sense when related to a customer. Otherwise, it is
an arbitrary piece of information. Let’s look at how you may model this.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Customer  
{  
    public int Id { get; set; }  
    public required string Name { get; set; }  
    public required Address Address { get; set; }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you may notice, the &lt;code&gt;Address&lt;/code&gt; property is used within the &lt;code&gt;Customer&lt;/code&gt; definition. Folks familiar with EF Core might
assume that there would be an &lt;code&gt;Addresses&lt;/code&gt; table, and in previous versions of EF Core, that would have been the case.&lt;/p&gt;

&lt;p&gt;In EF Core 8, the modeling process lets us map an &lt;code&gt;Address&lt;/code&gt; directly to columns within a &lt;code&gt;Customers&lt;/code&gt; table.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-SQL&quot;&gt;create table main.Customers
(
    Id               INTEGER not null
        constraint PK_Customers
            primary key autoincrement,
    Name             TEXT    not null,
    Address_City     TEXT    not null,
    Address_Country  TEXT    not null,
    Address_Line1    TEXT    not null,
    Address_Line2    TEXT,
    Address_PostCode TEXT    not null
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-ef8-rc1/&quot;&gt;According to the initial release notes&lt;/a&gt;, Complex types have
certain characteristics:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Types are not identified or tracked by a key value.&lt;/li&gt;
  &lt;li&gt;Must only exist as part of the entity and not directly have a &lt;code&gt;DbSet&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Can be value or reference types (records or classes).&lt;/li&gt;
  &lt;li&gt;Can share the same instance across multiple properties* (be careful).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final bullet states that the same instance is only shared during the manipulation process of in-memory objects. Once
the data is read back out, the newly tracked objects will be different instances. This is important because you may
encounter unexpected issues if you’re operating under false assumptions.&lt;/p&gt;

&lt;p&gt;So, how do you implement a complex type?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[ComplexType]
public class Address
{
    public required string Line1 { get; set; }
    public string? Line2 { get; set; }
    public required string City { get; set; }
    public required string Country { get; set; }
    public required string PostCode { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You add a &lt;code&gt;ComplexType&lt;/code&gt; attribute, of course. Again, note that this class does not have any key.&lt;/p&gt;

&lt;h2 id=&quot;saving-complex-types&quot;&gt;Saving Complex Types&lt;/h2&gt;

&lt;p&gt;Using a complex type is as you’d expect. Let’s take a look at a quick usage sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Database db = new();

// Complex Type storage of Address
var customer = new Customer
{
    Name = &quot;Khalid Abuhakmeh&quot;,
    Address = new()
    {
        Line1 = &quot;1 Fantasy Lane&quot;,
        City = &quot;Los Angeles&quot;,
        Country = &quot;USA&quot;,
        PostCode = &quot;90210&quot;,
    }
};
db.Customers.Add(customer);
await db.SaveChangesAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we look at the &lt;code&gt;Insert&lt;/code&gt; SQL statement, we can see a straightforward command.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt; INSERT INTO &quot;Customers&quot; (&quot;Name&quot;, &quot;Address_City&quot;, &quot;Address_Country&quot;, &quot;Address_Line1&quot;, &quot;Address_Line2&quot;, &quot;Address_PostCode&quot;)
      VALUES (@p0, @p1, @p2, @p3, @p4, @p5)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s one less table needed for our insert statements. That’s great news! What about querying the same model?&lt;/p&gt;

&lt;p&gt;Let’s perform the query &lt;code&gt;db.Customers.FirstOrDefault()&lt;/code&gt; and see what we get.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT &quot;c&quot;.&quot;Id&quot;, &quot;c&quot;.&quot;Name&quot;, &quot;c&quot;.&quot;Address_City&quot;, &quot;c&quot;.&quot;Address_Country&quot;, &quot;c&quot;.&quot;Address_Line1&quot;, &quot;c&quot;.&quot;Address_Line2&quot;, &quot;c&quot;.&quot;Address_PostCode&quot;
FROM &quot;Customers&quot; AS &quot;c&quot;
LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! Querying a single table is great news again.&lt;/p&gt;

&lt;p&gt;We can even write LINQ queries like you’d expect from any previous &lt;code&gt;DbContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var result = await db
    .Customers
    .Where(x =&amp;gt; x.Id == customer.Id)
    .Select(x =&amp;gt; x.Address)
    .FirstOrDefaultAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The previous LINQ statement produces the following SQL.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT &quot;c&quot;.&quot;Address_City&quot;, &quot;c&quot;.&quot;Address_Country&quot;, &quot;c&quot;.&quot;Address_Line1&quot;, &quot;c&quot;.&quot;Address_Line2&quot;, &quot;c&quot;.&quot;Address_PostCode&quot;
  FROM &quot;Customers&quot; AS &quot;c&quot;
  WHERE &quot;c&quot;.&quot;Id&quot; = @__customer_Id_0
  LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is awesome.&lt;/p&gt;

&lt;p&gt;A quick note about performance claims, it’s important to test any optimization and performance improvements in your own
codebase. While generally less tables involved in a transaction are better, there are scenarios that can be less
performant. For example, if you use Complex Types to create a monsterous 500+ column table, then you might want to
reconsider your approach and it &lt;em&gt;might&lt;/em&gt; be less performant than inserting into multiple tables.&lt;/p&gt;

&lt;p&gt;Here’s the &lt;code&gt;DbContext&lt;/code&gt; for completeness.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace EntityFrameworkCoreEight;

public class Database : DbContext
{
    public DbSet&amp;lt;Customer&amp;gt; Customers =&amp;gt; Set&amp;lt;Customer&amp;gt;();
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        =&amp;gt; optionsBuilder
            .UseSqlite(&quot;Data Source= database.db&quot;)
            .LogTo(Console.Write);
}

public class Customer
{
    public int Id { get; set; }
    public required string Name { get; set; }
    public required Address Address { get; set; }
}


[ComplexType]
public class Address
{
    public required string Line1 { get; set; }
    public string? Line2 { get; set; }
    public required string City { get; set; }
    public required string Country { get; set; }
    public required string PostCode { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Complex types allow you to reduce table sprawl, increase insert performance, and speed up query times. There are many
opportunities to review existing schemas and optimize your database. It’s still important to realize you might be
dealing with reference objects, so be careful about how you assign and modify objects that may be shared. There are
still some outstanding issues with Complex Types, but they are not critical show-stoppers. One of the issues is support
for inheritance. It is planned for future versions, but I can live without it now.
Despite the minor issues, this is an excellent addition to Entity Framework Core 8.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this blog post, and as always, cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 13 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/increase-performance-with-complex-types-in-entity-framework-core-8</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/increase-performance-with-complex-types-in-entity-framework-core-8</guid>
        
        <category>dotnet,</category>
        
        <category>entity-framework</category>
        
        
      </item>
    
      <item>
        <title>HTML Web Components with Vanilla JavaScript and ASP.NET Core</title>
        <description>&lt;p&gt;A general fog of “I hate JavaScript” hovers over the .NET development shops worldwide. While it’s understandable that
JavaScript can sometimes be annoying, it has grown significantly recently. One of the areas more ASP.NET Core developers
should take note of is Web Components. Web Components allow you to create custom HTML elements for your views that can
be one-off or reusable.&lt;/p&gt;

&lt;p&gt;With Blazor, ASP.NET Core developers are being exposed to component-based development, but the approach I am going to
show you today uses a technique called &lt;strong&gt;HTML web components&lt;/strong&gt;. Unlike Blazor components, these components wrap existing
HTML and enhance the contents into something with interactivity. Let’s take a look.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-are-html-web-components&quot;&gt;What are HTML Web Components?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.jim-nielsen.com/2023/html-web-components/&quot;&gt;Web developer Jim Nielsen wrote a blog post titled “Html Web Components”&lt;/a&gt;
where he compares the React component model with what he feels is a better way to write Web Components. His &lt;code&gt;UserAvatar&lt;/code&gt;
example might look familiar to Blazor developers.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;UserAvatar
  src=&quot;https://example.com/path/to/img.jpg&quot;
  alt=&quot;...&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re getting into web components, you might be tempted to write your web components using this approach, but you
might be causing unnecessary issues. What is a &lt;code&gt;UserAvatar&lt;/code&gt;? What elements compose this component? How do I style it?&lt;/p&gt;

&lt;p&gt;Instead, consider a wrapper component that can enhance the child elements nested within.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;user-avatar&amp;gt;
  &amp;lt;img src=&quot;https://example.com/path/to/img.jpg&quot; alt=&quot;...&quot; /&amp;gt;
&amp;lt;/user-avatar&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are multiple benefits to this approach:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Since elements already exist in the DOM, they can be processed immediately.&lt;/li&gt;
  &lt;li&gt;Team members can see all the elements and work with them accordingly.&lt;/li&gt;
  &lt;li&gt;Progressive enhancement. If the Javascript fails on start-up, you still have HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, instead of encapsulating HTML within a component, write your HTML web components to augment existing markup.
It’s a fantastic technique, and thanks to Jim Nielsen for their blog post. Now, let’s see how we can use this in ASP.NET
Core.&lt;/p&gt;

&lt;h2 id=&quot;the-blazor-counter-html-web-component&quot;&gt;The Blazor Counter HTML Web Component&lt;/h2&gt;

&lt;p&gt;I’ll be recreating Blazor’s counter component to show it doesn’t take much additional effort to write an HTML Web
Component. Let’s start with the HTML markup, as it’s the most straightforward implementation part.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;vanilla-counter 
    count=&quot;0&quot; 
    href=&quot;@Url.Page(&quot;Index&quot;, &quot;Count&quot;)&quot;&amp;gt;
    &amp;lt;h1&amp;gt;Counter&amp;lt;/h1&amp;gt;
    &amp;lt;p role=&quot;status&quot;&amp;gt;
        Current count: &amp;lt;span role=&quot;figure&quot;&amp;gt;0&amp;lt;/span&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;
        Click me
    &amp;lt;/button&amp;gt;
&amp;lt;/vanilla-counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note: All web components must have a &lt;code&gt;-&lt;/code&gt; in the name to be valid. This is to avoid conflicts with current and future
HTML elements.&lt;/p&gt;

&lt;p&gt;We have an endpoint that will increment the count for us. I am using an endpoint to show that even HTML Web components
can connect to the server, but they can be anything you’d like. If you can write it in JavaScript, a web component can
do it. Let’s look at the backend implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebComponentsSample.Pages;

[IgnoreAntiforgeryToken]
public class IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger) : PageModel
{
    public void OnGet()
    {
    }

    public IActionResult OnPostCount(int count)
    {
        return Content($&quot;{++count}&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, let’s write our HTML Web Component. It will be the &lt;code&gt;vanilla-counter&lt;/code&gt; element we see above. In a &lt;code&gt;Counter.js&lt;/code&gt; file,
add the following code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;export class Counter extends HTMLElement {
    static observedAttributes = [&quot;count&quot;, &quot;href&quot;]
    
    /* lifecycle events */
    connectedCallback() {
        console.log(&apos;created&apos;);
        this.$button.addEventListener(&quot;click&quot;, this.increment)
    }

    disconnectedCallback() {
        console.log(&apos;destroyed&apos;);
        this.$button.removeEventListener(&quot;click&quot;, this.increment)
    }

    attributeChangedCallback(name, oldValue, newValue) {
        if (name === &quot;count&quot;) {
            this.$figure.innerHTML = `${this.#count}`;
        }
    }

    increment = () =&amp;gt; {
        this.$button.disabled = true;

        let formData = new URLSearchParams();
        formData.append(&quot;count&quot;, this.#count);

        fetch(this.#href, {
           method: &apos;POST&apos;,
           headers: {
               &apos;Content-Type&apos;: &apos;application/x-www-form-urlencoded&apos;
           },
           body: formData
        }).then((response) =&amp;gt; {
            return response.text();
        }).then((data) =&amp;gt; {
            this.#count = parseInt(data);
            this.$button.disabled = false;
            console.log(&apos;clicked&apos;, this.#count);
        });
    }
    get $button() {
        return this.querySelector(&quot;button&quot;);
    }

    get $figure() {
        return this.querySelector(&apos;[role=&quot;figure&quot;]&apos;);
    }

    get #count() {
        return parseInt(this.getAttribute(&quot;count&quot;));
    }

    set #count(value) {
        this.setAttribute(&quot;count&quot;, value.toString());
    }
    
    get #href() {
        return this.getAttribute(&quot;href&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The essential elements, from top to bottom, of this class include the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code&gt;observedAttributes&lt;/code&gt; opts into watching specific attributes for the &lt;code&gt;attributeChangedCallback&lt;/code&gt; method. When these
attributes change in the DOM, the callback gets invoked.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;connectedCallback&lt;/code&gt; and &lt;code&gt;disconnectedCallback&lt;/code&gt; methods are lifecycle events invoked when the element is added and
removed from the DOM. This is important for dynamic element creation as you want to unregister any event listeners to
avoid memory leaks.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;increment&lt;/code&gt; is our logic, which calls the ASP.NET Core endpoint and returns the incremented value.&lt;/li&gt;
  &lt;li&gt;The rest of the class are helper getters and setters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We need to change our &lt;code&gt;site.js&lt;/code&gt; file to import our &lt;code&gt;Counter.js&lt;/code&gt; class and register the custom element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import {Counter} from &quot;./Counter.js&quot;;

window.customElements.define(&quot;vanilla-counter&quot;, Counter);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll also want to change the &lt;code&gt;_Layout.cshtml&lt;/code&gt; file to make sure the &lt;code&gt;site.js&lt;/code&gt; file is loaded as a &lt;code&gt;module&lt;/code&gt;, which will
allow us to use the &lt;code&gt;import&lt;/code&gt; keyword.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;~/js/site.js&quot;
        type=&quot;module&quot;
        asp-append-version=&quot;true&quot;&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see what it looks like in the browser.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/misc/html-web-component-aspnetcore-blazor-counter-sample.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;html web component working in aspnet core application&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;2830&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pretty
cool. &lt;a href=&quot;https://github.com/khalidabuhakmeh/WebComponentsSample/tree/main&quot;&gt;You can also try the HTML Web Component sample on my GitHub repository&lt;/a&gt;.
In the screenshot you can see the HTML component is triggering fetch requests to our ASP.NET Core backend.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The web platform has come a long way, and this approach could be helpful to folks building web experiences. The process
of building components is relatively straightforward, works with any technology stack, and has advantages regarding
progressive enhancement.&lt;/p&gt;

&lt;p&gt;I want to thank Jim Nielsen again for the excellent blog post and inspiration for this post. As always, thanks for
reading, and cheers. :)&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/html-web-components-with-vanilla-javascript-and-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/html-web-components-with-vanilla-javascript-and-aspnet-core</guid>
        
        <category>dotnet,</category>
        
        <category>javascript</category>
        
        
      </item>
    
      <item>
        <title>.NET Tasks, List&apos;s ForEach, and Problems</title>
        <description>&lt;p&gt;I was scrolling the Mastodon timeline when I noticed a fellow .NET
developer, &lt;a href=&quot;https://fosstodon.org/@billseipel&quot;&gt;Bill Seipel&lt;/a&gt;, having an unexpected experience with &lt;code&gt;List.ForEach&lt;/code&gt;
and &lt;code&gt;async/await&lt;/code&gt;. &lt;a href=&quot;https://fosstodon.org/@billseipel/111500572831442889&quot;&gt;At first glance&lt;/a&gt;, I thought he was modifying
the collection he was iterating over, but then I realized the issue was much more subtle.&lt;/p&gt;

&lt;p&gt;In this post, we’ll discuss what’s happening in a recreation of his code and how you might fix it.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;listforeach-and-tasks-lead-to-problems&quot;&gt;List.ForEach and Tasks lead to problems&lt;/h2&gt;

&lt;p&gt;For those unaware, the &lt;code&gt;List&lt;/code&gt; type has a &lt;code&gt;ForEach&lt;/code&gt; method, which allows the user to pass an &lt;code&gt;Action&amp;lt;T&amp;gt;&lt;/code&gt;. The method
passes the iteration’s item, allowing you to execute something similar to a &lt;code&gt;foreach&lt;/code&gt; method. In a sense, it’s syntactic
sugar. In another, it’s a relic before &lt;code&gt;async/await&lt;/code&gt;. Let’s see an example code that can get you in trouble.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;List&amp;lt;string&amp;gt; projects = new();  
List&amp;lt;string&amp;gt; measures = [&quot;cm&quot;, &quot;m&quot;, &quot;km&quot;];  
  
measures.ForEach(async x =&amp;gt;  
{  
     var result = await GetResultOfMeasure(x);  
     projects.Add(result);  
});  
  
Console.WriteLine(projects.Count);  
  
async Task&amp;lt;string&amp;gt; GetResultOfMeasure(string s)  
{  
     await Task.Delay(100);  
     return $&quot;Measured as {s}&quot;;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at the code, we see an &lt;code&gt;async/await&lt;/code&gt;, so what’s the problem? Well, let’s run the code and see what the result
is.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What?! Why did we get a result of &lt;code&gt;0&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;If you’re using a tool like &lt;a href=&quot;https://www.jetbrains.com/resharper/&quot;&gt;ReSharper&lt;/a&gt;
or &lt;a href=&quot;https://www.jetbrains.com/rider/&quot;&gt;JetBrains Rider&lt;/a&gt; you’ll have seen a warning around the &lt;code&gt;async&lt;/code&gt; keyword.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Avoid using &apos;async&apos; lambda when delegate type returns &apos;void&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oops! While the &lt;code&gt;Action&lt;/code&gt; uses &lt;code&gt;async/await&lt;/code&gt; semantics, nothing awaits the iterative process. This means our iterations
may or may not be complete by the time we reach the &lt;code&gt;Console.WriteLine&lt;/code&gt; statement. Since we use &lt;code&gt;Task.Delay&lt;/code&gt;, it’s
likely we won’t.&lt;/p&gt;

&lt;p&gt;If you’re using something that fluctuates in performance, you will likely pull out your hair due to indeterminate
behavior.&lt;/p&gt;

&lt;p&gt;So, what’s the fix?&lt;/p&gt;

&lt;h2 id=&quot;fixing-listforeach-with-foreachasync&quot;&gt;Fixing List.ForEach with ForEachAsync&lt;/h2&gt;

&lt;p&gt;The most straightforward solution is not to use &lt;code&gt;ForEach&lt;/code&gt; but to use a simple for each iteration instead.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;List&amp;lt;string&amp;gt; projects = new();
List&amp;lt;string&amp;gt; measures = [&quot;cm&quot;, &quot;m&quot;, &quot;km&quot;];

foreach (var measure in measures)
{
     var result = await GetResultOfMeasure(measure);
     projects.Add(result);
}

Console.WriteLine(projects.Count);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But honestly, where’s the fun in that?! Another approach is to write a &lt;code&gt;ForEachAsync&lt;/code&gt; extension method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class ListExtension
{
     public static async Task ForEachAsync&amp;lt;T&amp;gt;(
          this List&amp;lt;T&amp;gt; collection, 
          Func&amp;lt;T, Task&amp;gt; action)
     {
          foreach (var i in collection) await action(i);
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here, you can tweak the original sample code to be sure to await the entire iterative process.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;List&amp;lt;string&amp;gt; projects = new();
List&amp;lt;string&amp;gt; measures = [&quot;cm&quot;, &quot;m&quot;, &quot;km&quot;];

await measures.ForEachAsync(async x =&amp;gt;
{
     var result = await GetResultOfMeasure(x);
     projects.Add(result);
});

Console.WriteLine(projects.Count);

async Task&amp;lt;string&amp;gt; GetResultOfMeasure(string s)
{
     await Task.Delay(100);
     return $&quot;Measured as {s}&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you have it. Pretty cool, right?!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This particular issue is insidious as it all compiles and generally looks “correct.” With good tooling, like that
provided by JetBrains, you get a hint as to a potential issue lurking in your code, but it doesn’t scream at you since
it’s still code that compiles. It might make sense for .NET to include a &lt;code&gt;ForEachAsync&lt;/code&gt; method on &lt;code&gt;List&lt;/code&gt;, but at this
point, it might also make sense to &lt;code&gt;Obsolete&lt;/code&gt; the method entirely since it likely does more harm than good.&lt;/p&gt;

&lt;p&gt;What do you think? Let me know if you’ve ever run into this
issue. &lt;a href=&quot;https://fosstodon.org/@billseipel/111500572831442889&quot;&gt;You can see the full thread on Mastodon here, along with debugging videos describing what is happening.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my work with friends and colleagues. Cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 30 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dotnet-tasks-lists-foreach-and-problems</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dotnet-tasks-lists-foreach-and-problems</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>How To Use Blazor Server-Rendered Components with HTMX</title>
        <description>&lt;p&gt;A few new tricks have shipped with the .NET 8 release, and I’d like to take this time to experiment with them.
Specifically, I wanted to see if folks investing in a Blazor component library could still use the excellent HTMX
library. If you want to write even less JavaScript, this blog post will be right up your alley.&lt;/p&gt;

&lt;p&gt;This post will explore how to take a server-rendered component and give it some client-side flair without needing web
sockets or web assembly. We’ll even explore rewriting the &lt;code&gt;Counter&lt;/code&gt; component found in the Blazor template and building
it with HTMX in mind. Let’s go!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-htmx&quot;&gt;What is HTMX?&lt;/h2&gt;

&lt;p&gt;For folks familiar with Blazor’s interactive server mode, SignalR, aka Web sockets, the &lt;a href=&quot;https://htmx.org/&quot;&gt;HTMX&lt;/a&gt; model isn’t much different.&lt;/p&gt;

&lt;p&gt;The client communicates with the server, and the server retains stateful information. The big difference is that HTMX
takes a hypermedia approach, meaning it leans on the web’s traditional request/response nature. There are no persistent
connections between the client and the server. Any DOM element can initiate a request, wait for the server to process
it, and then respond with appropriate HTML. Once the HTML payload is received, it is swapped into the current DOM. While
the concept is simple to understand, it is powerful in practice.&lt;/p&gt;

&lt;h2 id=&quot;what-are-blazor-server-rendered-components&quot;&gt;What are Blazor Server-Rendered Components?&lt;/h2&gt;

&lt;p&gt;With the .NET 8 release, folks can opt-in
to &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-8.0#render-modes&quot;&gt;multiple render modes&lt;/a&gt;.
The first in the list of render modes is &lt;code&gt;Static&lt;/code&gt;, although that’s not entirely accurate.&lt;/p&gt;

&lt;p&gt;Static rendering implies you could compile components and assets into HTML at build time. In the case of Blazor, “
Static” rendering is more comparable to its contemporary approaches of MVC and Razor Pages. When a request to a page or
component is made, the server renders the component and its component graph and then responds with HTML.&lt;/p&gt;

&lt;p&gt;These Blazor components are all HTML, meaning they can only use HTML features and not the same interactive model you may
expect from &lt;code&gt;Interactive Server&lt;/code&gt; or &lt;code&gt;Interactive WebAssembly&lt;/code&gt; modes.&lt;/p&gt;

&lt;p&gt;The advantage to these Components is they are lightweight payloads, fast to render, and can even be streamed via stream
rendering.&lt;/p&gt;

&lt;h2 id=&quot;lets-use-htmx-with-blazor&quot;&gt;Let’s Use HTMX with Blazor&lt;/h2&gt;

&lt;p&gt;Before we port our &lt;code&gt;Counter&lt;/code&gt; component to use HTMX, we must set up our project to make Blazor play nicely with HTMX.&lt;/p&gt;

&lt;p&gt;The first step is to add HTMX to our &lt;code&gt;App.razor&lt;/code&gt; file. This is the app shell file which has our HTML structure.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;  
&amp;lt;html lang=&quot;en&quot;&amp;gt;  
  
&amp;lt;head&amp;gt;  
    &amp;lt;meta charset=&quot;utf-8&quot;/&amp;gt;  
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&amp;gt;  
    &amp;lt;base href=&quot;/&quot;/&amp;gt;  
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;bootstrap/bootstrap.min.css&quot;/&amp;gt;  
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;app.css&quot;/&amp;gt;  
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;BlazorHtmx.styles.css&quot;/&amp;gt;  
    &amp;lt;link rel=&quot;icon&quot; type=&quot;image/png&quot; href=&quot;favicon.png&quot;/&amp;gt;  
  
    &amp;lt;script defer src=&quot;_framework/blazor.web.js&quot;&amp;gt;&amp;lt;/script&amp;gt;  
    &amp;lt;script defer src=&quot;https://unpkg.com/htmx.org@1.9.8&quot;&amp;gt;&amp;lt;/script&amp;gt;  
    &amp;lt;script defer src=&quot;js/htmx-blazor.js&quot;&amp;gt;&amp;lt;/script&amp;gt;  
    &amp;lt;HeadOutlet/&amp;gt;  
&amp;lt;/head&amp;gt;  
&amp;lt;body&amp;gt;  
&amp;lt;Routes/&amp;gt;  
&amp;lt;/body&amp;gt;  
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll also need to write a bit of JavaScript to tie into Blazor’s enhanced rendering mode.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// An enhanced load allows users to navigate between different pages  
Blazor.addEventListener(&quot;enhancedload&quot;, function () {  
    // HTMX need to reprocess any htmx tags because of enhanced loading  
    htmx.process(document.body);  
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s set up our &lt;code&gt;HtmxCounter&lt;/code&gt; component. In a file, add the following Blazor component code. You’ll notice that
HTMX uses &lt;code&gt;hx-*&lt;/code&gt; attributes to define the behavior of DOM elements. It’s easy to pick up and can add functionality
quickly. (Not to brag, but I got this sample working on the first try. 🤩)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;&amp;lt;div class=&quot;counter&quot;&amp;gt;
    &amp;lt;p role=&quot;status&quot;&amp;gt;Current count: @State.Value&amp;lt;/p&amp;gt;
    &amp;lt;button class=&quot;btn btn-primary&quot;
            hx-post=&quot;/count&quot;
            hx-target=&quot;closest .counter&quot;
            hx-swap=&quot;outerHTML&quot;&amp;gt;
        Click me
    &amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

@code {
    [Parameter, EditorRequired] 
    public HtmxCounterState State { get; set; } = new();
    
    public class HtmxCounterState
    {
        public int Value { get; set; } = 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s look at our endpoint holding on to state. &lt;strong&gt;Note that this use of state management is only for demo
purposes. I recommend user-scoped state management like a database limited to a single user.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your Blazor’s &lt;code&gt;Program.cs&lt;/code&gt; file, you’ll need to register the state for our component.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c#&quot;&gt;builder.Services
    .AddSingleton&amp;lt;HtmxCounter.HtmxCounterState&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we’ll need the endpoint to increment and render our component HTML fragment.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c#&quot;&gt;app.MapPost(&quot;/count&quot;,
    (HtmxCounter.HtmxCounterState value) =&amp;gt;
    {
        value.Value++;
        return new RazorComponentResult&amp;lt;HtmxCounter&amp;gt;(
            new { State = value }
        );
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, let’s add our component to a Blazor server-rendered page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/&quot;
@inject HtmxCounter.HtmxCounterState CounterState

&amp;lt;PageTitle&amp;gt;Home&amp;lt;/PageTitle&amp;gt;

&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;

&amp;lt;div class=&quot;mb-4&quot;&amp;gt;
    &amp;lt;HtmxCounter State=&quot;CounterState&quot;/&amp;gt;
&amp;lt;/div&amp;gt;

@code {
    protected override void OnInitialized()
    {
        // reset counter on page reloads
        CounterState.Value = 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see what happens when we load our page.&lt;/p&gt;

&lt;video controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
    &lt;source src=&quot;https://github.com/khalidabuhakmeh/BlazorHtmx/raw/main/sample-video.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;That’s pretty cool. From a client perspective, you can’t tell which implementation uses WebSockets and which is using
HTMX. That’s amazing if you ask me. The HTMX implementation will also be cheaper in the long run as it requires no more
infrastructure than you currently have.&lt;/p&gt;

&lt;p&gt;If you want to check out the sample, you can get the solution
on &lt;a href=&quot;https://github.com/khalidabuhakmeh/BlazorHtmx&quot;&gt;my GitHub repository and a few more samples of using HTMX with Blazor&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Server-rendered components are an excellent addition to the Blazor toolbox and open up the possibility of using your
component library with something as cool as HTMX. I hope you try this sample and let me know what you think.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading my blog posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-blazor-server-rendered-components-with-htmx</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-blazor-server-rendered-components-with-htmx</guid>
        
        <category>Blazor,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How to use IAsyncEnumerable with Blazor Stream Rendering</title>
        <description>&lt;p&gt;With the release of .NET 8, one killer feature will immediately increase the responsiveness of your APIs and Blazor
applications: the ability to stream responses. Yes, you could stream responses before, but it’s never been easier with
support for &lt;code&gt;IAsyncEnumerable&lt;/code&gt; on API endpoints and the use of &lt;code&gt;StreamRenderingAttribute&lt;/code&gt; on your Blazor United
applications.&lt;/p&gt;

&lt;p&gt;This post will explore why you want to use &lt;code&gt;IAsyncEnumerable&lt;/code&gt; and &lt;code&gt;StreamRendering&lt;/code&gt; to get the fastest &lt;strong&gt;Time to first
byte (TTFB)&lt;/strong&gt; out of your ASP.NET Core web applications. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-iasyncenumerable&quot;&gt;What is IAsyncEnumerable?&lt;/h2&gt;

&lt;p&gt;The interface &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; is a newish interface designed with the idea that retrieving each element within the
iteration is an asynchronous task. This is different than a typical &lt;code&gt;Task&amp;lt;IEnumerable&amp;gt;&lt;/code&gt; as the operation to retrieve the
enumerable is considered one step. If you’ve used any data-access layer, you’ve likely invoked methods
like &lt;code&gt;ToListAsync&lt;/code&gt; or &lt;code&gt;ToArrayAsync&lt;/code&gt;, invoking a request to your database and materializing the result in a single
operation. Thinking about the same operation with &lt;code&gt;IAsyncEnumerable&lt;/code&gt;, the process will first execute the query and then
materialize each record as you enumerate through the collection. This allows you to start using data as it is received
rather than waiting for data to buffer in memory. This leads to more efficient use of resources and faster response
times.&lt;/p&gt;

&lt;p&gt;Let’s take a look at a simple example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;await foreach (var number in RangeAsync(1, 100))
{
    Console.WriteLine(number);
}

static async IAsyncEnumerable&amp;lt;Number&amp;gt; RangeAsync(int start, int count)
{
    for (int i = 0; i &amp;lt; count; i++)
    {
        await Task.Delay(i);
        yield return new Number(start + i);
    }
}

record Number(int Value);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice that &lt;code&gt;IAsyncEnumerable&lt;/code&gt; also has C# syntax support with the availability of &lt;code&gt;await foreach&lt;/code&gt;. That makes it
straightforward to consume in an existing codebase.&lt;/p&gt;

&lt;h2 id=&quot;what-is-stream-rendering&quot;&gt;What is Stream Rendering?&lt;/h2&gt;

&lt;p&gt;While recently added to Blazor, stream rendering is not a new concept. Most browser clients support
a &lt;code&gt;Transfer-Encoding&lt;/code&gt; of &lt;code&gt;chunked&lt;/code&gt;. We can get an idea of what this means to web developers
from &lt;a href=&quot;https://en.wikipedia.org/wiki/Chunked_transfer_encoding&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Chunked transfer encoding is a streaming data transfer mechanism available in Hypertext Transfer Protocol version 1.1,
defined in RFC 9112 §7.1. In chunked transfer encoding, the data stream is divided into a series of non-overlapping “
chunks”. The chunks are sent out and received independently of one another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cool! As application developers, we can take advantage of this for both API endpoints and, in the case of Blazor, for
streaming HTML markup from our component-based pages.&lt;/p&gt;

&lt;p&gt;Let’s look at streaming from a Minimal API endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Hello World!&quot;);

app.MapGet(&quot;/range&quot;, () =&amp;gt; 
    Results.Ok(new
    {
        totalCount = 100,
        results = RangeAsync(1, 100)
    }));

app.Run();

static async IAsyncEnumerable&amp;lt;Number&amp;gt; RangeAsync(int start, int count)
{
    for (int i = 0; i &amp;lt; count; i++)
    {
        await Task.Delay(i);
        yield return new Number(start + i);
    }
}

record Number(int Value);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running this sample in a browser, you’ll see the &lt;code&gt;results&lt;/code&gt; get output to the page, even before getting a semantically
complete JSON object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s important to understand that a client must understand and support chunking to take advantage of the performance
benefits.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;stream-rendering-and-iasyncenumerable-for-blazor&quot;&gt;Stream Rendering and IAsyncEnumerable for Blazor&lt;/h2&gt;

&lt;p&gt;While Blazor supports stream rendering for HTML elements, you need to consider &lt;em&gt;how&lt;/em&gt; you’ll be invoking
an &lt;code&gt;IAsyncEnumerable&lt;/code&gt; within a component’s lifecycle. While you may be tempted to do the following in your Blazor
components, it will result in an error.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@* ERROR: The &apos;await foreach&apos; statement can only be used in a method or lambda marked with the &apos;async&apos; modifier *@
@await foreach (var forecast in forecasts)
{
	&amp;lt;tr&amp;gt;
		&amp;lt;td&amp;gt;@forecast.Date.ToShortDateString()&amp;lt;/td&amp;gt;
		&amp;lt;td&amp;gt;@forecast.TemperatureC&amp;lt;/td&amp;gt;
		&amp;lt;td&amp;gt;@forecast.TemperatureF&amp;lt;/td&amp;gt;
		&amp;lt;td&amp;gt;@forecast.Summary&amp;lt;/td&amp;gt;
	&amp;lt;/tr&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The correct approach to using &lt;code&gt;IAsyncEnumerable&lt;/code&gt; within a Blazor component comes down to three essential considerations:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A collection variable must first exist, as you’ll be appending to it, not replacing it altogether.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;IAsyncEnumerable&lt;/code&gt; must be awaited within an async component lifecycle method such as &lt;code&gt;OnInitializedAsync&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The method &lt;code&gt;StateHasChanged&lt;/code&gt; must be invoked to tell Blazor to flush HTML to the response. This can be after each
iteration or on some determined interval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see what that looks like in a sample. I’ve tweaked the &lt;code&gt;Weather.razor&lt;/code&gt; sample that comes with the Blazor template.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;/weather&quot;
@attribute [StreamRendering]

&amp;lt;PageTitle&amp;gt;Weather&amp;lt;/PageTitle&amp;gt;

&amp;lt;h1&amp;gt;Weather&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;This component demonstrates showing data.&amp;lt;/p&amp;gt;

@if (forecasts is { Count : 0 })
{
    &amp;lt;p&amp;gt;
        &amp;lt;em&amp;gt;Loading...&amp;lt;/em&amp;gt;
    &amp;lt;/p&amp;gt;
}
else
{
    &amp;lt;table class=&quot;table&quot;&amp;gt;
        &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;Date&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Temp. (C)&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Temp. (F)&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Summary&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
        @foreach (var forecast in forecasts)
        {
            &amp;lt;tr&amp;gt;
                &amp;lt;td&amp;gt;@forecast.Date.ToShortDateString()&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;@forecast.TemperatureC&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;@forecast.TemperatureF&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;@forecast.Summary&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
        }
        &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
}

@code {
	//1. the collection we&apos;ll be adding to
    private readonly List&amp;lt;WeatherForecast&amp;gt; forecasts = new();

    protected override async Task OnInitializedAsync()
    {
        forecasts.Clear();
        // 2. invoking the IAsyncEnumerable implementation
        await foreach (var forecast in GetForecasts())
        {
            forecasts.Add(forecast);
            // 3. Calling StateHasChanged to flush
            StateHasChanged();
        }
    }

    static async IAsyncEnumerable&amp;lt;WeatherForecast&amp;gt; GetForecasts()
    {
        var startDate = DateOnly.FromDateTime(DateTime.Now);
        var summaries = new[]
        {
            &quot;Freezing&quot;, &quot;Bracing&quot;, &quot;Chilly&quot;,
            &quot;Cool&quot;, &quot;Mild&quot;, &quot;Warm&quot;, &quot;Balmy&quot;,
            &quot;Hot&quot;, &quot;Sweltering&quot;, &quot;Scorching&quot;
        };

        for (var index = 0; index &amp;lt;= 5; index++)
        {
            await Task.Delay(1000);
            yield return new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            };
        }
    }

    private class WeatherForecast
    {
        public DateOnly Date { get; set; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
        public int TemperatureF =&amp;gt; 32 + (int)(TemperatureC / 0.5556);
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you have it. You are now using an &lt;code&gt;IAsyncEnumerable&lt;/code&gt; within stream rendering to get the most performance out of
your Blazor applications.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Streaming a response to the user can increase the perceived performance of your applications. Still, it’s important to
remember that you also need to improve the performance of your dependencies to get the most out of this approach. While
it may make your app more performant to stream HTML to the client as soon as possible, that effort can be undercut by a
slow dependency such as a database or web service. Give it a try, and let me know what performance increases you see in
your applications.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-iasyncenumerable-with-blazor-stream-rendering</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-iasyncenumerable-with-blazor-stream-rendering</guid>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>View Transitions API with ASP.NET Core and HTMX</title>
        <description>&lt;p&gt;I recently
hosted &lt;a href=&quot;https://youtu.be/Yb2eONhEE5k?si=yP66WI9SxvkpXkiM&quot;&gt;JetBrains JavaScript Day with guest speaker Fred K. Schott of Astro fame&lt;/a&gt;,
who spoke about the View Transitions API being introduced in modern browsers. You should watch the video, which will
give you a primer for this blog post; frankly, it’s such an incredible presentation.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to mix three remarkable web technologies to get a fantastic user experience with little
to no effort on your part. Of course, I’m speaking about using ASP.NET Core Razor Pages, HTMX, and View Transitions to
smooth the transition between pages and reduce the perceived performance of those hops between pages.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-are-view-transitions&quot;&gt;What are View Transitions?&lt;/h2&gt;

&lt;p&gt;View Transitions is a new approach that gives web designers more native-like animated transitions between navigation
events. These navigation events can be complete page transitions or elements moving from one part of the page to
another. As web developers, we can focus on performance practices while allowing the web platform to do a lot of the
heavy lifting of animation.&lt;/p&gt;

&lt;p&gt;While I could explain the technical nitty-gritty of the View Transitions
API, &lt;a href=&quot;https://developer.chrome.com/docs/web-platform/view-transitions/&quot;&gt;Jake Archibald did an excellent job explaining it better than I ever could.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short, we can decide how a page visually transitions from one state to another using JavaScript and CSS animations.&lt;/p&gt;

&lt;h2 id=&quot;why-htmx&quot;&gt;Why HTMX?&lt;/h2&gt;

&lt;p&gt;While an argument could be made that you don’t need HTMX here, there are a few reasons I recommend it when working with
ASP.NET Core Razor Pages.&lt;/p&gt;

&lt;p&gt;First, the &lt;code&gt;hx-boost&lt;/code&gt; feature of HTMX allows us to squeeze more performance out of our page transitions. The &lt;code&gt;body&lt;/code&gt;
element from a new request is swapped into our existing page, thus skipping the expensive step of parsing CSS and
JavaScript resources.&lt;/p&gt;

&lt;p&gt;Second, since HTMX 1.9.0, we can specify an additional &lt;code&gt;transition:true&lt;/code&gt; value on &lt;code&gt;hx-swap&lt;/code&gt; attributes to opt in to view
transitions. This is simpler than the imperative style mentioned in the previous explainer above.&lt;/p&gt;

&lt;p&gt;Finally, HTMX brings more valuable approaches we’ll use as we build our ASP.NET Core application.&lt;/p&gt;

&lt;h2 id=&quot;view-transition-sample&quot;&gt;View Transition Sample&lt;/h2&gt;

&lt;p&gt;Let’s first see this sample in action and walk through the steps necessary to get View Transitions into your
application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/khalidabuhakmeh/HtmxViewTransitions/raw/main/results.gif&quot; alt=&quot;example&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool. Each navigation performs a transition with a cool slide animation, which is commonly used in native-style
applications. Additionally, the visual shell of the site does not animate but instead stays in place.&lt;/p&gt;

&lt;p&gt;Let’s walk through the steps to get this into your applications, and you’ll be surprised that no C# will be involved in
the following guide.&lt;/p&gt;

&lt;p&gt;The first step is to add HTMX to your &lt;code&gt;head&lt;/code&gt; element. You can install HTMX via an asset package manager like NPM or a
CDN provider. For simplicity, I’ve included the CDN version below.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;https://unpkg.com/htmx.org@1.9.8&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, you’ll want to apply the &lt;code&gt;hx-boost&lt;/code&gt; attribute to a container that has anchor tags as children. In the case of this
demo, I added the attribute to the &lt;code&gt;body&lt;/code&gt; tag as I want all anchors to perform the View Transition animation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;body hx-boost=&quot;true&quot; hx-swap=&quot;transition:true&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll also notice the &lt;code&gt;body&lt;/code&gt; tag has an &lt;code&gt;hx-swap&lt;/code&gt; attribute with a &lt;code&gt;transition:true&lt;/code&gt; value. This marks our element as
the root View Transition element.&lt;/p&gt;

&lt;p&gt;Finally, we need to add some CSS animations and values to our site’s stylesheet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@keyframes fade-in {
  from { opacity: 0; }
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes slide-from-right {
  from { transform: translateX(90px); }
}

@keyframes slide-to-left {
  to { transform: translateX(-90px); }
}

/* define animations for the old and new content */
::view-transition-old(slide-it) {
  animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
  600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(slide-it) {
  animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
  600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}

body {
  margin-bottom: 60px;
  view-transition-name: slide-it;
}

.navbar {
  view-transition-name: main-header-text;
  animation: none;
  mix-blend-mode: normal;
}

footer {
  view-transition-name: footer;
  animation: none;
  mix-blend-mode: normal;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ve created some basic animations that we apply to each element. Each rule must get a unique &lt;code&gt;view-transition-name&lt;/code&gt;
value so that the View Transitions API knows how to identify each element uniquely.&lt;/p&gt;

&lt;p&gt;That’s it! We now have the implementation of the example you saw previously.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It’s shockingly simple to get a pleasant native-like experience in your ASP.NET Core applications with a bit of HTMX and
take advantage of the advancements in the web platform. The View Transitions API is still experimental and not fully
supported across all browsers, but most Chromium-based browsers and Firefox already support it.&lt;/p&gt;

&lt;p&gt;If you’d like to run this sample on your development
environment, &lt;a href=&quot;https://github.com/khalidabuhakmeh/HtmxViewTransitions/tree/main&quot;&gt;I’ve created a GitHub repository where you can clone and try it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading my blog posts and sharing them with colleagues. Cheers.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://htmx.org/essays/view-transitions/&quot;&gt;HTMX View Transitions Example&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/web-platform/view-transitions/&quot;&gt;Smooth and simple transitions with the View Transitions API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/view-transition-name&quot;&gt;view-transition-name&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/Yb2eONhEE5k?si=yP66WI9SxvkpXkiM&quot;&gt;JetBrains JavaScript Day with guest speaker Fred K. Schott&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 09 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/view-transitions-api-with-aspnet-core-and-htmx</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/view-transitions-api-with-aspnet-core-and-htmx</guid>
        
        <category>css,</category>
        
        <category>aspnet,</category>
        
        <category>htmx</category>
        
        
      </item>
    
      <item>
        <title>How to Write a .NET Markdig Extension for Markdown Processing</title>
        <description>&lt;p&gt;Markdown is a powerful writing format with simplicity at its core. It’s no surprise that it is as popular as it is since
it can help authors focus more on the art of writing rather than the aesthetics of their work. While there is a standard
specification for the language, there are extensions to the Markdown syntax that can enhance the authoring experience in
niche contexts. For example, LaTex support for mathematics, improved media support for online services like YouTube, and
diagram support via Mermaid for all aspiring software architects.&lt;/p&gt;

&lt;p&gt;With Markdown, if you can write it, you can parse and translate it to a desired output. In this post, we’ll explore
the &lt;a href=&quot;https://github.com/xoofx/markdig&quot;&gt;Markdig&lt;/a&gt; library by author &lt;a href=&quot;https://github.com/xoofx&quot;&gt;Alexandre Mutel&lt;/a&gt;, which is
.NET’s fastest and most powerful CommonMark-compliant Markdown parser. Most importantly, it’s also extensible!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-markdown-and-markdig&quot;&gt;What is Markdown and Markdig?&lt;/h2&gt;

&lt;p&gt;For folks new to Markdown, it is a text-based format used to help writers focus on the structure and content of their
work rather than the aesthetics of the work.&lt;/p&gt;

&lt;p&gt;Aesthetics include font choices, colors, font sizing, and overall layout concerns. While aesthetics can help tell a more
immersive story, they can hinder the writing process if introduced too early.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.markdownguide.org/&quot;&gt;Markdown&lt;/a&gt; focuses on some familiar structural writing tropes and allows you to express
them using simplified structures and symbols amongst code. These include headers, links, emphasis, lists, and more.
Markdown gets its name because, typically, the format is converted into markup, also known as HTML. Although, Markdown
can have many targets, including PDFs, presentation slides, and much more. Your imagination is the limit.&lt;/p&gt;

&lt;p&gt;As the introduction mentions, &lt;a href=&quot;https://github.com/xoofx/markdig&quot;&gt;Markdig&lt;/a&gt; is a .NET library aimed at helping developers
process and transform markdown files. It’s a drop-in and ready library for most needs but also has extensibility
options.&lt;/p&gt;

&lt;h2 id=&quot;writing-a-markdig-inline-parser-extension&quot;&gt;Writing a Markdig Inline Parser Extension&lt;/h2&gt;

&lt;p&gt;There are three parts to writing an extension for Markdig: Markdown syntax, the processing pipeline, and the syntax
parser. We’ll walk through all three parts and why they are essential. Let’s start with first describing the intent of
our extension.&lt;/p&gt;

&lt;p&gt;Given the following syntax, we want to parse any matching token and replace it with a GitHub username link.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;this is a link to [github:khalidabuhakmeh]  
and [github:maartenba]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with a resulting output of HTML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;this is a link to &amp;lt;a href=&quot;https://github.com/khalidabuhakmeh&quot;/&amp;gt;khalidabuhakmeh&amp;lt;/a&amp;gt;
and &amp;lt;a href=&quot;https://github.com/maartenba&quot;/&amp;gt;maartenba&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To parse this with markdown with Markdig, you must first install the NuGet package &lt;code&gt;Markdig&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;dotnet add package Markdig
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we’ll need to set up a &lt;code&gt;MarkdownPipeline&lt;/code&gt; using a &lt;code&gt;MarkdownPipelineBuilder&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.RegularExpressions;
using Markdig;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers;
using Markdig.Syntax.Inlines;

var pipeline = new MarkdownPipelineBuilder()
    .Use&amp;lt;GitHubUserProfileExtension&amp;gt;()
    .Build();

var html = Markdown
    .ToHtml(&quot;&quot;&quot;
            this is a link to [github:khalidabuhakmeh]
            and [github:maartenba]
            &quot;&quot;&quot;, pipeline);

Console.WriteLine(html);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The pipeline is a series of syntax parsers that run over the markdown document, switching out the syntax for the final
output.&lt;/p&gt;

&lt;p&gt;You’ll notice the mention of &lt;code&gt;GitHubUserProfileExtension&lt;/code&gt; when building the pipeline. This is our new extension. Let’s
take a look at the implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class GitHubUserProfileExtension : IMarkdownExtension
{
    public void Setup(MarkdownPipelineBuilder pipeline)
    {
        if (!pipeline.InlineParsers.Contains&amp;lt;GitHubUserProfileParser&amp;gt;())
        {
            pipeline.InlineParsers.Insert(0, new GitHubUserProfileParser());
        }
    }

    public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The extension class is the opportunity to add the &lt;code&gt;GitHubUserProfileParser&lt;/code&gt; to the collection of &lt;code&gt;InlineParsers&lt;/code&gt;.
Parsers take incoming markdown syntax and process the value to its final result.&lt;/p&gt;

&lt;p&gt;In my case, I insert the new parser at the beginning of the collection. Parsers execute in the order they are
registered. Since I’m reusing the syntax of a link in Markdown, I want to ensure I can process the token before any
other parser does. If your parser operates on unique syntax, you can add the parser anywhere in the collection.&lt;/p&gt;

&lt;p&gt;Now, let’s get to the parser.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public partial class GitHubUserProfileParser : InlineParser
{
    public GitHubUserProfileParser()
    {
        OpeningCharacters = new[] { &apos;[&apos; };
    }
    
    public override bool Match(InlineProcessor processor, ref StringSlice slice)
    {
        var precedingCharacter = slice.PeekCharExtra(-1);
        if (!precedingCharacter.IsWhiteSpaceOrZero())
        {
            return false;
        }
        
        var regex = GithubTagRegex();
        var match = regex.Match(slice.ToString());
        
        if (!match.Success)
        {
            return false;
        }
        
        var username = match.Groups[&quot;username&quot;].Value;
        var literal = $&quot;&amp;lt;a href=\&quot;https://github.com/{username}\&quot;/&amp;gt;{username}&amp;lt;/a&amp;gt;&quot;;
        
        processor.Inline = new HtmlInline(literal)
        {
            Span =
            {
                Start = processor.GetSourcePosition(slice.Start, out var line, out var column)
            },
            Line = line,
            Column = column,
            IsClosed = true
        };
        processor.Inline.Span.End = processor.Inline.Span.Start + match.Length - 1;
        slice.Start += match.Length;
        return true;
    }

    [GeneratedRegex(@&quot;\[github:(?&amp;lt;username&amp;gt;\w+)]&quot;)]
    private static partial Regex GithubTagRegex();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a few crucial elements to a parser, but none more critical than the &lt;code&gt;OpeningCharacters&lt;/code&gt; collection. These
characters are what trigger entry into the &lt;code&gt;Match&lt;/code&gt; method. Without setting this value, your parser will be responsible
for parsing &lt;strong&gt;all the text&lt;/strong&gt;. I made this mistake, but Alexandre Mutel was kind enough to point out my mistake.&lt;/p&gt;

&lt;p&gt;Next, in the &lt;code&gt;Match&lt;/code&gt; method, we get a reference to a &lt;code&gt;StringSlice&lt;/code&gt;, which allows us to check if we’ve matched our
expected token. You can look forward and backward here in the provided string, or my case, use a
source-generated &lt;code&gt;Regex&lt;/code&gt; to match the token.&lt;/p&gt;

&lt;p&gt;Once matched, you can create an inline representation of the value to be replaced. I want to replace the token with an
anchor tag pointing to a user’s GitHub profile. You also need to calculate where the token begins and ends, and you can
do that using the &lt;code&gt;GetSourcePosition&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I also make sure that I set &lt;code&gt;IsClosed&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. This lets other parsers know that I’ve handled this token and that
they should not attempt to modify the token. This depends on your use case, but for this one, this is the end of
processing for this token.&lt;/p&gt;

&lt;p&gt;Finally, we set the &lt;code&gt;slice.Start&lt;/code&gt; position after the token so we don’t keep processing it. If you’re experiencing an
exception with a “The parser is in an invalid infinite loop” message, you’ve likely forgotten to move the starting
position past the current token.&lt;/p&gt;

&lt;p&gt;It’s that easy! Here’s the complete sample in its entirety.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.RegularExpressions;
using Markdig;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers;
using Markdig.Syntax.Inlines;

var pipeline = new MarkdownPipelineBuilder()
    .Use&amp;lt;GitHubUserProfileExtension&amp;gt;()
    .Build();

var html = Markdown
    .ToHtml(&quot;&quot;&quot;
            this is a link to [github:khalidabuhakmeh]
            and [github:maartenba]
            &quot;&quot;&quot;, pipeline);

Console.WriteLine(html);

public class GitHubUserProfileExtension : IMarkdownExtension
{
    public void Setup(MarkdownPipelineBuilder pipeline)
    {
        if (!pipeline.InlineParsers.Contains&amp;lt;GitHubUserProfileParser&amp;gt;())
        {
            pipeline.InlineParsers.Insert(0, new GitHubUserProfileParser());
        }
    }

    public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
    {
    }
}

public partial class GitHubUserProfileParser : InlineParser
{
    public GitHubUserProfileParser()
    {
        OpeningCharacters = new[] { &apos;[&apos; };
    }
    
    public override bool Match(InlineProcessor processor, ref StringSlice slice)
    {
        var precedingCharacter = slice.PeekCharExtra(-1);
        if (!precedingCharacter.IsWhiteSpaceOrZero())
        {
            return false;
        }
        
        var regex = GithubTagRegex();
        var match = regex.Match(slice.ToString());
        
        if (!match.Success)
        {
            return false;
        }
        
        var username = match.Groups[&quot;username&quot;].Value;
        var literal = $&quot;&amp;lt;a href=\&quot;https://github.com/{username}\&quot;/&amp;gt;{username}&amp;lt;/a&amp;gt;&quot;;
        
        processor.Inline = new HtmlInline(literal)
        {
            Span =
            {
                Start = processor.GetSourcePosition(slice.Start, out var line, out var column)
            },
            Line = line,
            Column = column,
            IsClosed = true
        };
        processor.Inline.Span.End = processor.Inline.Span.Start + match.Length - 1;
        slice.Start += match.Length;
        return true;
    }

    [GeneratedRegex(@&quot;\[github:(?&amp;lt;username&amp;gt;\w+)]&quot;)]
    private static partial Regex GithubTagRegex();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I love Markdown, and Markdig helps .NET developers embrace the wonders of the specification. The extensibility of
Markdig also allows .NET developers to go beyond the CommonMark specification and build unique Markdown flavors for
their specific purpose. As you’ve seen, it only takes a few classes to extend the functionality of a markdown document
beyond the already impressive extensions included with Markdig.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and thanks to &lt;a href=&quot;https://github.com/xoofx&quot;&gt;Alexandre Mutel&lt;/a&gt; and other Markdig contributors
for their fantastic work. Thanks for reading and sharing my posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-write-a-dotnet-markdig-extension-for-markdown-processing</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-write-a-dotnet-markdig-extension-for-markdown-processing</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Faster .NET Database Integration Tests with Respawn and xUnit</title>
        <description>&lt;p&gt;The nuances of data access are myriad, so when writing tests around complex data scenarios, I recommend just working
with the actual database. Over time, you’ll find yourself with more valuable tests but, often, relatively slower tests
compared to their in-memory alternatives. Like all things, there are trade-offs, but you can still strategize in making
your tests faster.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to take advantage of xUnit class fixtures and the OSS library Respawn to manage the
state of your database across tests. This will help speed up your tests when faster steps replace a few expensive ones.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-respawn&quot;&gt;What is Respawn?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jbogard/Respawn?tab=readme-ov-file&quot;&gt;Respawn&lt;/a&gt; is a utility library designed to help developers reset
databases to an “initial state”. With some configuration, Respawn can intelligently reset a database for testing use
cases.&lt;/p&gt;

&lt;p&gt;Other strategies might employ complete database tear-downs, complex transaction management, or expensive Docker
containerization strategies. When mixed with your database management strategy around database migrations, look-up
tables, and other stateful database elements, the overhead can compound over time and hurt the developer feedback loop
many crave from an excellent test suite.&lt;/p&gt;

&lt;p&gt;Respawn allows you to choose which tables and schemas to ignore in the reset process.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var respawner = await Respawner.CreateAsync(connection, new RespawnerOptions
{
    TablesToIgnore = new Table[]
    {
        &quot;sysdiagrams&quot;,
        &quot;tblUser&quot;,
        &quot;tblObjectType&quot;,
        new Table(&quot;MyOtherSchema&quot;, &quot;MyOtherTable&quot;)
    },
    SchemasToExclude = new []
    {
        &quot;RoundhousE&quot;
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It also supports multiple database providers, including Microsoft SQL Server, Postgres, MySQL, Oracle, and Informix.&lt;/p&gt;

&lt;p&gt;Using xUnit fixtures (which we’ll see later), you only need to call a single method to reset the database.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;await respawner.ResetAsync(&quot;MyConnectionStringName&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After every reset, your database will return to its initial state and be ready for another round of test assertions.&lt;/p&gt;

&lt;h2 id=&quot;xunit-respawn-fixture&quot;&gt;xUnit ReSpawn Fixture&lt;/h2&gt;

&lt;p&gt;I’ve created &lt;a href=&quot;https://github.com/khalidabuhakmeh/respawn-sample&quot;&gt;a sample Respawn and xUnit project&lt;/a&gt; with all the code
in this blog post so you can try it out in your development environment.&lt;/p&gt;

&lt;p&gt;For folks following along in the post, I’m using a &lt;code&gt;GlobalUsing.cs&lt;/code&gt; file for namespaces and some C# 12 (.NET 8)
features. Here are the required namespaces.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;global using Dapper;
global using Dapper.Contrib.Extensions;
global using Microsoft.Data.SqlClient;
global using Respawn;
global using Xunit;
global using Xunit.Abstractions;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When working with Respawn, you’ll need a fixture. In the world of xUnit, fixtures are shared resources across test
classes. In the case of this sample, we’ll create a &lt;code&gt;DatabaseFixture&lt;/code&gt;, which will manage the database using
a &lt;code&gt;Respawner&lt;/code&gt; instance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace Spawn;

// ReSharper disable once ClassNeverInstantiated.Global
public class DatabaseFixture : IAsyncLifetime
{
    private const string DatabaseName = &quot;test&quot;;
    
    private readonly Dictionary&amp;lt;string, string&amp;gt; connectionStrings = new()
    {
        { DatabaseName, $&quot;Data Source=localhost,11433;Database={DatabaseName};User Id=sa;Password=Pass123!;Encrypt=FALSE;&quot; },
        { &quot;master&quot;, &quot;Data Source=localhost,11433;Database=master;User Id=sa;Password=Pass123!;Encrypt=FALSE;&quot; }
    };

    public async Task&amp;lt;SqlConnection&amp;gt; GetOpenConnectionAsync(string databaseName = DatabaseName)
    {
        var sqlConnection = new SqlConnection(connectionStrings[databaseName]);
        await sqlConnection.OpenAsync();
        return sqlConnection;
    }

    private Respawner respawn = null!;

    public async Task InitializeAsync()
    {
        await MigrateAsync();

        respawn = await Respawner.CreateAsync(connectionStrings[DatabaseName],
            new RespawnerOptions
            {
                DbAdapter = DbAdapter.SqlServer
            });
    }

    private async Task MigrateAsync()
    {
        // only doing this for the sample,
        // you&apos;ll likely already have the database created somewhere
        {
            try
            {
                await using var connection = await GetOpenConnectionAsync(&quot;master&quot;);
                await connection.ExecuteAsync(
                    // lang=SQL
                    $&quot;&quot;&quot;
                     IF NOT EXISTS (SELECT [name] FROM sys.databases WHERE [name] = N&apos;{DatabaseName}&apos;)
                        CREATE DATABASE {DatabaseName};
                     &quot;&quot;&quot;
                );
            }
            catch (SqlException e)
            {
                throw new Exception(&quot;Create and run the container found in the docker-compose.yml&quot;, e);
            }
        }

        {
            await using var connection = await GetOpenConnectionAsync();
            await connection.ExecuteAsync(
                // lang=SQL
                &quot;&quot;&quot;
                IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N&apos;[dbo].[People]&apos;) AND type in (N&apos;U&apos;))
                  BEGIN
                      CREATE TABLE People
                      (
                          ID INT PRIMARY KEY IDENTITY,
                          FirstName NVARCHAR(50),
                          LastName NVARCHAR(50),
                          Age INT,
                          Email NVARCHAR(255)
                      );
                  END;
                &quot;&quot;&quot;);
        }
            
    }

    public Task ResetAsync()
        =&amp;gt; respawn.ResetAsync(connectionStrings[DatabaseName]);

    public async Task DisposeAsync()
    {
        await using var connection = await GetOpenConnectionAsync(&quot;master&quot;);
        await connection.ExecuteAsync(
            // lang=SQL
            $&quot;&quot;&quot;
            IF EXISTS (SELECT [name] FROM sys.databases WHERE [name] = N&apos;{DatabaseName}&apos;)
            BEGIN
                ALTER DATABASE {DatabaseName}
                SET SINGLE_USER -- Disallow multi-user access.
                WITH ROLLBACK IMMEDIATE -- Rollback any transaction in progress.
                DROP DATABASE {DatabaseName};
            END;
            &quot;&quot;&quot;
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must utilize the &lt;code&gt;IAsyncLifetime&lt;/code&gt; interface in xUnit to call Respawn’s asynchronous methods. I’ve also added a helper
method of &lt;code&gt;GetOpenConnectionAsync&lt;/code&gt; to make it easier to write tests using the fixture.&lt;/p&gt;

&lt;p&gt;Note that the migration strategy in the fixture does not use any particular approach commonly found in the .NET
ecosystem. You’ll likely use EF Core migrations, Roundhouse, DbUp, or another migration strategy. Adjust the code for
your particular use case. I’ve also taken the steps to create the database if it does not currently exist. Creating the
database might be optional based on your development environment.&lt;/p&gt;

&lt;p&gt;Now let’s use our fixture in a new test class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace Spawn;

public class RespawnTests(DatabaseFixture database, ITestOutputHelper output)
    : IClassFixture&amp;lt;DatabaseFixture&amp;gt;, IAsyncLifetime
{
    [Fact]
    public async Task Can_Insert_Person_Into_People()
    {
        await using var connection = await database.GetOpenConnectionAsync();
        await connection.InsertAsync&amp;lt;Person&amp;gt;(new()
        {
            FirstName = &quot;Khalid&quot;,
            LastName = &quot;Abuhakmeh&quot;,
            Age = 40,
            Email = &quot;khalid@example.com&quot;
        });

        var person = await connection.QueryFirstAsync&amp;lt;Person&amp;gt;(&quot;select top 1 * from people&quot;);
        var total = await connection.ExecuteScalarAsync(&quot;select count(ID) from People&quot;);

        output.WriteLine($&quot;{person.FirstName} says hi!&quot;);

        Assert.NotNull(person);
        Assert.Equal(expected: 1, actual: total);
    }

    [Fact]
    public async Task People_Table_Is_Always_Empty()
    {
        await using var connection = await database.GetOpenConnectionAsync();
        var person = await connection.QueryFirstOrDefaultAsync&amp;lt;Person&amp;gt;(&quot;select top 1 * from people&quot;);
        Assert.Null(person);
    }

    public Task InitializeAsync()
        =&amp;gt; Task.CompletedTask;

    public Task DisposeAsync()
        =&amp;gt; database.ResetAsync();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use the &lt;code&gt;IAsyncLifetime&lt;/code&gt; interface again to ensure that our database is reset after each test is run. In
the &lt;code&gt;DisposeAsync&lt;/code&gt; method, we invoke the fixture’s &lt;code&gt;ResetAsync&lt;/code&gt; method, which resets our database to its initial state.
That’s it! Easy peasy.&lt;/p&gt;

&lt;p&gt;On my development machine, the total time of the tests is about &lt;code&gt;250ms&lt;/code&gt;, with the bulk of the time spent creating and
tearing down my database for the sample. In your use case, you can cut the cost of database creation and teardown by
creating the database outside the scope of the class fixture.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With Respawn and xUnit class fixtures, you can significantly improve your integration test performance and get a tighter
feedback loop. You also get the added value of knowing your code is testing against the “real” thing. Integration tests
can help catch behavioral changes in the underlying database technology and find issues with queries, and database
features you’d otherwise miss when working with stubs.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and please give the sample a try. I’ve set it up so you can run through this sample
in seconds, and it should give you a great jumping-off point.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/faster-dotnet-database-integration-tests-with-respawn-and-xunit</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/faster-dotnet-database-integration-tests-with-respawn-and-xunit</guid>
        
        <category>dotnet,</category>
        
        <category>xunit</category>
        
        
      </item>
    
      <item>
        <title>MemoizR - Declarative Structured Concurrency for C#</title>
        <description>&lt;p&gt;Recently, I’ve been focusing on the front-end side of building web applications with topics like React Hooks and Angular
Signals. It’s a fascinating data model that can make working with data dependency graphs much more straightforward.&lt;/p&gt;

&lt;p&gt;To my surprise, other folks in the .NET community have also been inspired by the work happening in the frontend space.
While scanning NuGet, I found &lt;a href=&quot;https://github.com/timonkrebs/MemoizR&quot;&gt;MemoizR&lt;/a&gt;, a library that takes inspiration from
the frontend world to bring the concept of dynamic lazy memoization to .NET developers.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see a short example using the library and explain the sample output. Let’s go!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-memoizr&quot;&gt;What is MemoizR?&lt;/h2&gt;

&lt;p&gt;According to the author, Timon Krebs, MemoizR is a declarative structured concurrency implementation for .NET that
simplifies (and enhances) standard data flow methods across multiple threads. These methods include error handling,
branching logic, and data mutation. Doing so helps developers manage concurrency more efficiently for simple to complex
multi-thread scenarios.&lt;/p&gt;

&lt;p&gt;Critical features of MemoizR include dynamic lazy memoization, which determines if values need to be reevaluated.
Another feature is declarative structured concurrency, which makes building and handling scenarios more straightforward.
Regarding scenarios, MemoizR also builds a dependency graph, which helps reduce unnecessary computations if a particular
branch has not been affected by changes. These features also lead to automatic synchronization and improved overall
performance.&lt;/p&gt;

&lt;p&gt;Let’s look at an example application.&lt;/p&gt;

&lt;h2 id=&quot;hello-memoizr-sample&quot;&gt;Hello MemoizR Sample&lt;/h2&gt;

&lt;p&gt;To start with MemoizR, you must install the latest version into a new Console project. As of this post, MemoizR is still
in prerelease, so you should enable prerelease visibility in your NuGet tool window. You may also run the following
command.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotnet add package MemoizR --version 0.1.0-rc4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you install the dependency, paste the following code into the &lt;code&gt;Program.cs&lt;/code&gt; file of the project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MemoizR;

var f = new MemoFactory();

var one = f.CreateSignal(2);
var two = f.CreateSignal(2);

var squareOne = f.CreateMemoizR(async () =&amp;gt;
{
    var value = await one.Get();
    Console.WriteLine($&quot;Square One: {value}&quot;);
    return Math.Pow(value, 2);
});

var squareTwo = f.CreateMemoizR(async () =&amp;gt;
{
    var value = await two.Get();
    Console.WriteLine($&quot;Square Two: {value}&quot;);
    return Math.Pow(value, 2);
});

var final = f.CreateMemoizR(async () =&amp;gt;
{
    var result = await squareOne.Get() + await squareTwo.Get();
    Console.WriteLine(&quot;Add Squares&quot;);
    return result;
});


while (true)
{
    Console.Write($&quot;Set one (current: {await one.Get()}):&quot;);
    var user1 = Console.ReadLine();
    if (user1 is not null &amp;amp;&amp;amp; int.TryParse(user1, out var value)) {
        await one.Set(value);
    }
    
    Console.Write($&quot;Set two (current: {await two.Get()}):&quot;);
    var user2 = Console.ReadLine();
    if (user2 is not null &amp;amp;&amp;amp; int.TryParse(user2, out value)) {
        await two.Set(value);
    }

    var result = await final.Get();
    Console.WriteLine($&quot;Result is {result}.\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This sample aims to show the dependency graph in action by changing the values of &lt;code&gt;one&lt;/code&gt; and &lt;code&gt;two&lt;/code&gt;. We’ll execute the
following scenarios from this app:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Initial run&lt;/li&gt;
  &lt;li&gt;Change the value of &lt;code&gt;one&lt;/code&gt; and not &lt;code&gt;two&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Change the value of &lt;code&gt;two&lt;/code&gt; and not &lt;code&gt;one&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Change no values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We should see the following outputs reflecting which parts of the graph were executed.&lt;/p&gt;

&lt;p&gt;Let’s start with the initial run’s output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Set one (current: 2):
Set two (current: 2):
Square One: 2
Square Two: 2
Add Squares
Result is 8.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see all parts of our graph executed. Now, let’s only change the value of &lt;code&gt;one&lt;/code&gt;. You’ll notice only half of the
graph dependent on the &lt;code&gt;one&lt;/code&gt; value is executed.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Set one (current: 2):3
Set two (current: 2):
Square One: 3
Add Squares
Result is 13.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let’s only change &lt;code&gt;two&lt;/code&gt;. We should see the opposite is true.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Set one (current: 3):
Set two (current: 2):1
Square Two: 1
Add Squares
Result is 10.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, let’s not change any values. Our graph should not execute any nodes, as it’s value is unchanged.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Set one (current: 3):
Set two (current: 1):
Result is 10.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This library is still early but shows much promise for building complex multi-threaded scenarios where elements may or
may not change. As you say in the sample, the code is easy to follow and the flow is easily modifiable. I think the
author has something interesting here and I hope to see how they evolve it over time.&lt;/p&gt;

&lt;p&gt;I hope you give MemoizR a try and let me know what you think. As always, thanks for reading and sharing my posts.
Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 19 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/memoizr-declarative-structured-concurrency-for-csharp</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/memoizr-declarative-structured-concurrency-for-csharp</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Testing Typesense search with Testcontainers and .NET</title>
        <description>&lt;p&gt;Search is an essential part of any modern application. Without a first-class emphasis on great search, many applications
aren’t much better than a spreadsheet. Luckily for application developers, we’re spoiled for options for delivering an
excellent search experience to our users. One of the options I’ve been playing with recently is Typesense, which aims to
be an open-source alternative to commercial-service Algolia.&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at how you can play around with Typesense within the context of .NET using Testcontainers.
Testcontainers is a library that makes spinning up containers so simple you’ll wonder how you ever lived without it.
Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-typesense&quot;&gt;What is Typesense&lt;/h2&gt;

&lt;p&gt;Search is challenging to get right, with many commercial options. The most notable commercial offerings include
Elasticsearch and Algolia, which come with licensing costs or are search-as-a-service solutions. While great choices in
their own right, the options might not fit your particular goals for finding a search
solution. &lt;a href=&quot;https://typesense.org/&quot;&gt;Typesense&lt;/a&gt; is an open-source alternative to the aforementioned options, with many
great features developers expect from a search provider.&lt;/p&gt;

&lt;p&gt;Typesense provides development teams with a search engine that can perform search-as-you-type, autocomplete, faceted
navigation, geo-search, recommendations, and more. Developers can also run Typesense within a docker container within
their organization’s infrastructure. There are also SDKs for most languages that make managing a search index easier
from within your technology stack of choice. For folks reading this post, yes, there is a .NET SDK too.&lt;/p&gt;

&lt;p&gt;Typesense operates on a “batteries-included” philosophy, hoping to give developers all the essential features they need
right out of the box. This means you can get a “good enough” experience within minutes while having the ability to
fine-tune the experience over time.&lt;/p&gt;

&lt;p&gt;To take Typesense for a test drive, we’ll use Testcontainers to spin up an instance of the search provider and poke at
it.&lt;/p&gt;

&lt;h2 id=&quot;what-is-testcontainers&quot;&gt;What is Testcontainers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt; is an open-source framework for providing lightweight and disposable
instances of any imaginable dependency that can run within a Docker container. You can test against the actual
technology and avoid mocks and stubs altogether. This framework has a first-class .NET library to allow any developer to
pull a Docker image, configure a container instance, run it, and dispose of it.&lt;/p&gt;

&lt;p&gt;The following section, we will set up a unit test class using xUnit, Testcontainers, and Typesense.&lt;/p&gt;

&lt;h2 id=&quot;xunit-testcontainers-and-typesense-sample&quot;&gt;xUnit, Testcontainers, and Typesense sample&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note: The samples are using newer C# language features like primary constructors and target-type inference. If the
code doesn’t compile, you likely need set your language version to a newer version or adapt the code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’ll need to create a new xUnit class library with the following dependencies: &lt;code&gt;Testcontainers&lt;/code&gt;, &lt;code&gt;Typesense&lt;/code&gt;,
and &lt;code&gt;xUnit&lt;/code&gt;. Once these dependencies are added to the class library, we can start by creating a &lt;code&gt;TypesenseFixture&lt;/code&gt;
class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TypesenseFixture&lt;/code&gt; class will create the container and the configuration needed to connect to our container
instance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using Microsoft.Extensions.Options;
using Typesense;
using Typesense.Setup;
using Xunit;

namespace TypesenseWithTestcontainer;

public class TypesenseFixture: IAsyncLifetime
{
    private const int ContainerPort = 8108;
    private const string ApiKey = &quot;typesense-api-key&quot;;

    public TypesenseFixture()
    {
        TypesenseContainer = new ContainerBuilder()
            .WithImage(&quot;typesense/typesense:0.25.1&quot;)
            .WithPortBinding(ContainerPort, true)
            .WithEnvironment(&quot;TYPESENSE_API_KEY&quot;, ApiKey)
            .WithEnvironment(&quot;TYPESENSE_DATA_DIR&quot;, &quot;/tmp&quot;)
            .WithWaitStrategy(Wait.ForUnixContainer()
                .UntilHttpRequestIsSucceeded(r =&amp;gt; r
                    .ForPort(ContainerPort)
                    .ForPath(&quot;/health&quot;)
                    .WithHeader(&quot;TYPESENSE-API-KEY&quot;, ApiKey)
                )
            )
            .Build();
    }

    public Config ConnectionConfig { get; private set; }
    public IContainer TypesenseContainer { get; }

    public TypesenseClient GetClient()
    {
        var options = new OptionsWrapper&amp;lt;Config&amp;gt;(ConnectionConfig);
        var client = new TypesenseClient(options, new HttpClient());
        return client;
    }

    public async Task InitializeAsync()
    {
        await TypesenseContainer.StartAsync();
        
        var port = TypesenseContainer
            .GetMappedPublicPort(ContainerPort)
            .ToString();
        
        ConnectionConfig = new Config(
            new Node[] { new(TypesenseContainer.Hostname, port) },
            ApiKey
        );
    }

    public Task DisposeAsync()
        =&amp;gt; TypesenseContainer.DisposeAsync().AsTask();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Essential steps that are happening in the use of &lt;code&gt;ContainerBuilder&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We set the image name for &lt;code&gt;typesense/typesense:0.25.1&lt;/code&gt;. This name matches an image in the Docker image registry.&lt;/li&gt;
  &lt;li&gt;We bind the internal port &lt;code&gt;8081&lt;/code&gt; to a random port on our host.&lt;/li&gt;
  &lt;li&gt;We set the environment variables of &lt;code&gt;TYPESENSE_API_KEY&lt;/code&gt; and &lt;code&gt;TYPESENSE_DATA_DIR&lt;/code&gt;. These variables are required to
start up the container successfully.&lt;/li&gt;
  &lt;li&gt;We wait for Typesense to start by repeatedly hitting the &lt;code&gt;/health&lt;/code&gt; endpoint until the response is successful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the container has started successfully, we can use the container information to produce a Typesense configuration
for our client.&lt;/p&gt;

&lt;p&gt;Our first step is to see if we can call our instance of Typesense.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Json.Serialization;
using Typesense;
using Xunit;
using Xunit.Abstractions;

namespace TypesenseWithTestcontainer;

public class TypesenseTests(TypesenseFixture fixture, ITestOutputHelper output) :
    IClassFixture&amp;lt;TypesenseFixture&amp;gt;
{
    [Fact]
    public async Task CanQueryTypesenseForHealth()
    {
        var client = fixture.GetClient();
        var result = await client.RetrieveHealth();

        Assert.NotNull(result);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The preceding test should pass if everything is set up correctly. Let’s expand our test with a more fun Typesense
example.&lt;/p&gt;

&lt;p&gt;First, we’ll need a document to store in Typesense.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class Product(string id, string name, string manufacturer, double price)
{
	[JsonPropertyName(nameof(Id))]
	public string Id { get; set; } = id;
	[JsonPropertyName(nameof(Name))]
	public string Name { get; set; } = name;
	[JsonPropertyName(nameof(Manufacturer))]
	public string Manufacturer { get; set; } = manufacturer;
	[JsonPropertyName(nameof(Price))]
	public double Price { get; set; } = price;
	
	public static Product[] Samples { get; } = {
		new(&quot;1&quot;, &quot;iPhone 15&quot;, &quot;Apple&quot;, 1500),
		new(&quot;2&quot;, &quot;Pixel 8 Pro&quot;, &quot;Google&quot;, 1300),
		new(&quot;3&quot;, &quot;Playstation 5&quot;, &quot;Sony&quot;, 500),
		new(&quot;4&quot;, &quot;XBox Series X&quot;, &quot;Xbox&quot;, 500),
		new(&quot;5&quot;, &quot;Switch&quot;, &quot;Nintendo&quot;, 300)
	};
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Typesense uses &lt;code&gt;System.Text.Json&lt;/code&gt; with &lt;code&gt;CamelCase&lt;/code&gt; naming. In the case of my test, I wanted to retain the original
casing, so I used the &lt;code&gt;JsonPropertyName&lt;/code&gt; attribute to set the name of each field explicitly. The &lt;code&gt;Product&lt;/code&gt; class also
defines some sample data for use in our test.&lt;/p&gt;

&lt;p&gt;We’ll also want to add &lt;code&gt;IAsyncLifetime&lt;/code&gt; to our &lt;code&gt;TypesenseTests&lt;/code&gt; class. This will allow us to load our document
collection and clear it on each test.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public async Task InitializeAsync()
{
	var client = fixture.GetClient();

	var schema = new Schema(nameof(Product), new Field[]
	{
		new(nameof(Product.Id), FieldType.String),
		new(nameof(Product.Name), FieldType.String, false),
		new(nameof(Product.Manufacturer), FieldType.String, true, false, true),
		new(nameof(Product.Price), FieldType.Float, false)
	});

	await client.CreateCollection(schema);

	foreach (var product in Product.Samples) {
		await client.CreateDocument(nameof(Product), product);
	}
}

public async Task DisposeAsync()
{
	var client = fixture.GetClient();
	await client.DeleteCollection(nameof(Product));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, let’s add our test and search for a product.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[Fact]
public async Task CanSearchForProducts()
{
	var client = fixture.GetClient();

	var results = await client
		.Search&amp;lt;Product&amp;gt;(
			nameof(Product),
			new(&quot;Sony&quot;, nameof(Product.Manufacturer))
		);
	
	Assert.Equal(1, results.Hits.Count);
	
	var product = results.Hits[0].Document;
	Assert.Equal(&quot;Sony&quot;, product.Manufacturer);
	
	output.WriteLine($&quot;Found {product.Manufacturer} {product.Name} ({product.Price:C})&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome! Here’s the complete test class for improved clarity.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Json.Serialization;
using Typesense;
using Xunit;
using Xunit.Abstractions;

namespace TypesenseWithTestcontainer;

public class TypesenseTests(TypesenseFixture fixture, ITestOutputHelper output) :
    IClassFixture&amp;lt;TypesenseFixture&amp;gt;, IAsyncLifetime
{
    [Fact]
    public async Task CanQueryTypesenseForHealth()
    {
        var client = fixture.GetClient();
        var result = await client.RetrieveHealth();

        Assert.NotNull(result);
    }

    [Fact]
    public async Task CanSearchForProducts()
    {
        var client = fixture.GetClient();

        var results = await client
            .Search&amp;lt;Product&amp;gt;(
                nameof(Product),
                new(&quot;Sony&quot;, nameof(Product.Manufacturer))
            );
        
        Assert.Equal(1, results.Hits.Count);
        
        var product = results.Hits[0].Document;
        Assert.Equal(&quot;Sony&quot;, product.Manufacturer);
        
        output.WriteLine($&quot;Found {product.Manufacturer} {product.Name} ({product.Price:C})&quot;);
    }

    public class Product(string id, string name, string manufacturer, double price)
    {
        [JsonPropertyName(nameof(Id))]
        public string Id { get; set; } = id;
        [JsonPropertyName(nameof(Name))]
        public string Name { get; set; } = name;
        [JsonPropertyName(nameof(Manufacturer))]
        public string Manufacturer { get; set; } = manufacturer;
        [JsonPropertyName(nameof(Price))]
        public double Price { get; set; } = price;
        
        public static Product[] Samples { get; } = {
            new(&quot;1&quot;, &quot;iPhone 15&quot;, &quot;Apple&quot;, 1500),
            new(&quot;2&quot;, &quot;Pixel 8 Pro&quot;, &quot;Google&quot;, 1300),
            new(&quot;3&quot;, &quot;Playstation 5&quot;, &quot;Sony&quot;, 500),
            new(&quot;4&quot;, &quot;XBox Series X&quot;, &quot;Xbox&quot;, 500),
            new(&quot;5&quot;, &quot;Switch&quot;, &quot;Nintendo&quot;, 300)
        };
    }

    public async Task InitializeAsync()
    {
        var client = fixture.GetClient();

        var schema = new Schema(nameof(Product), new Field[]
        {
            new(nameof(Product.Id), FieldType.String),
            new(nameof(Product.Name), FieldType.String, false),
            new(nameof(Product.Manufacturer), FieldType.String, true, false, true),
            new(nameof(Product.Price), FieldType.Float, false)
        });

        await client.CreateCollection(schema);

        foreach (var product in Product.Samples) {
            await client.CreateDocument(nameof(Product), product);
        }
    }

    public async Task DisposeAsync()
    {
        var client = fixture.GetClient();
        await client.DeleteCollection(nameof(Product));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we can test the Typesense search engine from within .NET and explore the client’s capabilities.&lt;/p&gt;

&lt;p&gt;As a note, you should do your document initialization code less frequently and possibly within the fixture. Also,
explore xUnit’s &lt;code&gt;Collection&lt;/code&gt; attribute to reduce the amount of containers created for larger test suites.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Typesense is a promising solution for providing your users an outstanding search experience. By using Testcontainers
with the Typesense Docker image, you can quickly experiment with the capabilities of the search engine and what’s
possible.&lt;/p&gt;

&lt;p&gt;You can get the complete sample at
my &lt;a href=&quot;https://github.com/khalidabuhakmeh/TypesenseWithTestcontainer&quot;&gt;Typesense with Testcontainers GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this post gives you a good starting point to explore and iterate on your solutions. As always, thank you for
reading and sharing my posts. Cheers. :)&lt;/p&gt;
</description>
        <pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/testing-typesense-search-with-testcontainers-and-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/testing-typesense-search-with-testcontainers-and-dotnet</guid>
        
        <category>xunit,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>How to use Regular Expressions and Match Evaluators in .NET</title>
        <description>&lt;p&gt;Let’s face it, regular expressions are powerful and can be an immense pain in the butt to write. While crafting a regular expression to perform any input recognition is possible, it becomes exceedingly difficult when the matching rules require more complicated logic. In specific scenarios, doing an initial regular expression match is more straightforward, and then applying code logic to get the desired result.&lt;/p&gt;

&lt;p&gt;This post will look at a straightforward example of using &lt;code&gt;RegEx.Replace&lt;/code&gt; with the &lt;code&gt;MatchEvaluator&lt;/code&gt; to do a two-step replacement of matched tokens.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-regexreplace&quot;&gt;What is RegEx.Replace?&lt;/h2&gt;

&lt;p&gt;When attempting to replace tokens in a string, many developers will reach for &lt;code&gt;RegEx.Replace&lt;/code&gt;, which aims to take an input, a regular expression, and then returns are modified result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Regex.Replace(&quot;test&quot;, &quot;^test$&quot;, &quot;success&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The example works great for simple scenarios, as it is doing token replacement. But what about the following scenario?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Find all image filenames&lt;/li&gt;
  &lt;li&gt;Replace the filename and extension&lt;/li&gt;
  &lt;li&gt;Ignore any filename that doesn’t match a criteria.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is possible with a regular expression but can be complex with lookahead, lookbehind, and named groups. It is not easy for most developers to pull this off. How do we get the result that we want?&lt;/p&gt;

&lt;p&gt;Let’s look at a more readable way of solving the problem presented with &lt;code&gt;MatchEvaluator&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;working-with-matchevaluator&quot;&gt;Working with MatchEvaluator&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MatchEvaluator&lt;/code&gt; type is a delegate wrapper that expects a potentially mutated match result. The delegate can return any value based on the match and other logic a developer may add.&lt;/p&gt;

&lt;p&gt;Let’s look at a solution.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.RegularExpressions;  
  
string[] extensions = [&quot;.jpg&quot;, &quot;.gif&quot;];  
// lang=regex  
var pattern = @&quot;\w*\.(\w{3,4})&quot;;  
  
var original = &quot;test.webp, test-01.jpg and test-02.gif&quot;;  
var result = Regex.Replace(original, pattern, match =&amp;gt;  
{  
    var extension = Path.GetExtension(match.Value);  
    // if we don&apos;t need to do anything, return the original value  
    if (!extensions.Contains(extension)) return match.Value;  
    // convert value to a token with webp  
    var filename = Path.GetFileNameWithoutExtension(match.Value);  
    return $&quot;{filename}-converted.webp&quot;;  
}, RegexOptions.IgnoreCase);  
  
Console.WriteLine(result);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, the &lt;code&gt;MatchEvaluator&lt;/code&gt; delegate gets the &lt;code&gt;Match&lt;/code&gt;. At this point, we can write custom and complex logic to transform the match.&lt;/p&gt;

&lt;p&gt;Running the code above, returns the following result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;test.webp, test-01-converted.webp and test-02-converted.webp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you’re struggling to write that perfect &lt;code&gt;RegEx&lt;/code&gt; for token replacement, you might find it more straightforward to do it in two steps. First, write a simple-to-understand pattern, and then use &lt;code&gt;MatchEvalutor&lt;/code&gt; to get you to the finish line.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and thanks for reading.&lt;/p&gt;
</description>
        <pubDate>Tue, 05 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-regular-expressions-and-match-evaluators-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-regular-expressions-and-match-evaluators-in-dotnet</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Scriban for Text and Liquid Templating in .NET</title>
        <description>&lt;p&gt;Templating is a common approach to separating logic from presentation, and many options exist within the .NET ecosystem.
The most popular is the Razor engine used by ASP.NET Core, but it currently has some dependencies that make it difficult
to use consistently in many scenarios. That’s where alternative templating systems can provide value, as they typically
work with fewer, if any, external dependencies.&lt;/p&gt;

&lt;p&gt;As a big fan of &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;, &lt;a href=&quot;https://shopify.github.io/liquid/basics/introduction/&quot;&gt;Liquid&lt;/a&gt; is a
natural choice for
templating as it provides simple templating, types, iteration, control flow, and a suite of built-in helper methods.
It’s also very mature and has excellent documentation. So, I was excited to
try &lt;a href=&quot;https://github.com/scriban/scriban&quot;&gt;Scriban&lt;/a&gt; as a fast, robust, safe, and lightweight templating engine.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-scriban&quot;&gt;What is Scriban?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/scriban/scriban&quot;&gt;Scriban&lt;/a&gt; is the brainchild of &lt;a href=&quot;https://github.com/xoofx&quot;&gt;Alexandre Mutel&lt;/a&gt;, and is
touted as a scripting language and
engine for .NET with the primary purpose of text templating. It also provides a compatibility mode for parsing and
rendering Liquid templates. It’s vital to distinguish Scriban as a text templating engine, not just a web view engine.
Text templating implies it can be used to generate any text-based format, including but not limited to HTML. Outside of
.NET dependencies, Scriban is entirely free of external dependencies, with the option to source embed. This makes it
perfect for many app host options in the .NET ecosystem.&lt;/p&gt;

&lt;h2 id=&quot;getting-started-with-scriban&quot;&gt;Getting Started with Scriban&lt;/h2&gt;

&lt;p&gt;Let’s see what a &lt;em&gt;“Hello World”&lt;/em&gt; use case would look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// Parse a scriban template
var template = Template.Parse(&quot;Hello !&quot;);
var result = template.Render(new { Name = &quot;World&quot; }); 
// =&amp;gt; &quot;Hello World!&quot; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This could look more exciting, but it hints at some mind-blowing scenarios which we’ll see in the next section. Let’s
ramp it up.&lt;/p&gt;

&lt;h2 id=&quot;complex-liquid-scenario-with-scriban&quot;&gt;Complex Liquid Scenario with Scriban&lt;/h2&gt;

&lt;p&gt;As mentioned, Liquid is a commonly-used templating language used in the Ruby on Rails community. Shopify also uses it
for its online storefront platform. Let’s look at a complex C# example of a Liquid template and then break it down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: If you’re using &lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider&lt;/a&gt;, install
the &lt;a href=&quot;https://plugins.jetbrains.com/plugin/14388-liquid&quot;&gt;Liquid plugin&lt;/a&gt; to get Liquid syntax highlighting.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Scriban;  
using Scriban.Runtime;  
  
var script = new ScriptObject();  
script.Import(typeof(MyFunctions));  
script.Add(&quot;products&quot;, new Product[]  
{  
    new(&quot;Blue Socks&quot;, 10m, &quot;plain socks&quot;),  
    new(&quot;Gray Pants&quot;, 22m, &quot;regular ol&apos; pants&quot;),  
    new(&quot;Amazing T-Shirt&quot;, 24m, 
        &quot;the world&apos;s most fantastical t-shirt&quot;),  
});  
  
var context = new LiquidTemplateContext();  
context.PushGlobal(script);  
  
var template = Template.ParseLiquid(
    // lang=liquid
    &quot;&quot;&quot;
    &amp;lt;ul id=&apos;products&apos;&amp;gt;{% for product in products %}
        &amp;lt;li&amp;gt;
            &amp;lt;h2&amp;gt;{{ product.name | append_emoji }} ({{ product.price }})&amp;lt;/h2&amp;gt;
            &amp;lt;p&amp;gt;{{ product.description | truncate: 15, &quot;...&quot; }}&amp;lt;/p&amp;gt;
        &amp;lt;/li&amp;gt;{% endfor %}
    &amp;lt;/ul&amp;gt;
    &quot;&quot;&quot;);
  
var result = template.Render(context);  
  
Console.WriteLine(result);  
  
public static class MyFunctions  
{  
    public static string AppendEmoji(string input)  
        =&amp;gt; $&quot;{input} 🛍️&quot;;  
}  
  
public record Product(  
    string Name,  
    decimal Price,  
    string Description);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the start of of the code, we create a new &lt;code&gt;ScriptObject&lt;/code&gt;. This instance will contain all our variables and .NET
functions we’ll want to use in our template.&lt;/p&gt;

&lt;p&gt;The first step registers an &lt;code&gt;AppendEmoji&lt;/code&gt; method, which gets translated into &lt;code&gt;append_emoji&lt;/code&gt; by convention. All static
methods in the &lt;code&gt;MyFunctions&lt;/code&gt; class will be registered. You can expand your templating vocabulary with a few C# methods.&lt;/p&gt;

&lt;p&gt;Next, we add the &lt;code&gt;products&lt;/code&gt; global variable to our script. This collection will be used in the template to display our
product collection. These are plain old C# records.&lt;/p&gt;

&lt;p&gt;Finally, we get to the template parsing and rendering. You’ll notice the use of the &lt;code&gt;truncate&lt;/code&gt; filter in the template.
From my testing, most Liquid filters are available out of the box, which is helpful. When the template is parsed, we’re
ready to render it. Here, the call to &lt;code&gt;Render&lt;/code&gt; is provided the script context, which references our data and our
C# &lt;code&gt;AppendEmoji&lt;/code&gt; helper method.&lt;/p&gt;

&lt;p&gt;All that’s left is to see what the results look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;ul id=&apos;products&apos;&amp;gt;
    &amp;lt;li&amp;gt;
        &amp;lt;h2&amp;gt;Blue Socks 🛍️ (10)&amp;lt;/h2&amp;gt;
        &amp;lt;p&amp;gt;plain socks&amp;lt;/p&amp;gt;
    &amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;
        &amp;lt;h2&amp;gt;Gray Pants 🛍️ (22)&amp;lt;/h2&amp;gt;
        &amp;lt;p&amp;gt;regular ol&apos; ...&amp;lt;/p&amp;gt;
    &amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;
        &amp;lt;h2&amp;gt;Amazing T-Shirt 🛍️ (24)&amp;lt;/h2&amp;gt;
        &amp;lt;p&amp;gt;the world&apos;s ...&amp;lt;/p&amp;gt;
    &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s awesome!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/scriban/scriban&quot;&gt;Scriban&lt;/a&gt; looks like an excellent templating engine for the .NET ecosystem. With the
ability to use Liquid, it goes to a whole new level. The ability to inject variables and methods into the template is
also excellent. Please try it and let me know what scenarios you could use a text templating engine in.&lt;/p&gt;

&lt;p&gt;Thank you for reading and sharing my posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 28 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/scriban-for-text-and-liquid-templating-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/scriban-for-text-and-liquid-templating-in-dotnet</guid>
        
        <category>dotnet,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>ASP.NET Core PDF Previews and Downloads</title>
        <description>&lt;p&gt;Tell me if you’ve heard this one before. You spend months working with UI and UX experts, building what you think is the
most optimal means of displaying business information. You sit in a meeting with your stakeholders, demoing what you
created. Everything feels great, but then silence fills the room. A lone stakeholder raises their voice, “This is all
great, but can we get it in a PDF?”.&lt;/p&gt;

&lt;p&gt;The Portable Document Format (PDF) is in a heated race, with Excel spreadsheets as the most valuable file format in
business today. As a developer, you will inevitably be asked to compress everything into a file that business
individuals can share via email. Don’t fight it, but embrace it.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see the two approaches to transmitting PDF files through ASP.NET Core to get two different
behaviors: In-browser preview and downloads.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;generating-a-pdf-with-questpdf&quot;&gt;Generating a PDF with QuestPDF&lt;/h2&gt;

&lt;p&gt;While this post isn’t a tutorial for generating PDFs, you’ll need a way to generate PDFs to follow along. I recommend
using the &lt;a href=&quot;https://www.questpdf.com/&quot;&gt;QuestPDF library&lt;/a&gt;. The API is easy to get started with and will have you
generating PDF documents in no time. Also, their licensing costs are reasonable, ranging from a free community license
to an Enterprise license. That said, feel free to substitute any PDF-generating method you prefer.&lt;/p&gt;

&lt;p&gt;Here is the code for my PDF generation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private static byte[] GetPdfDocuments()  
{  
  var pdf =  
      Document.Create(container =&amp;gt;  
      {  
          container.Page(page =&amp;gt;  
          {  
              page.Size(PageSizes.A4);  
              page.Margin(2, Unit.Centimetre);  
              page.PageColor(Colors.White);  
              page.DefaultTextStyle(x =&amp;gt; x.FontSize(20));  

              page.Header()  
                  .Text(&quot;Hello PDF!&quot;)  
                  .SemiBold().FontSize(36)
                  .FontColor(Colors.Blue.Medium);  

              page.Content()  
                  .PaddingVertical(1, Unit.Centimetre)  
                  .Column(x =&amp;gt;
                  {  
                      x.Spacing(20);

                      x
                      .Item()
                      .Text(Placeholders.LoremIpsum());  
                      x
                      .Item()
                      .Image(Placeholders.Image(200, 100));  
                  });
              
              page.Footer()  
                  .AlignCenter()  
                  .Text(x =&amp;gt;  
                  {  
                      x.Span(&quot;Page &quot;);  
                      x.CurrentPageNumber();  
                  });            
          });        
  }).GeneratePdf();  
  
  return pdf;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, let’s move on to one of the first ways of transmitting a PDF to your user: previewing the file within the browser.&lt;/p&gt;

&lt;h2 id=&quot;previewing-a-pdf-file-in-the-browser&quot;&gt;Previewing a PDF File in the Browser&lt;/h2&gt;

&lt;p&gt;In this example, I’ll be using ASP.NET Core MVC, but this approach should work with Razor Pages and even Minimal APIs.
Adjust the code accordingly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public IActionResult Show()  
{  
    var pdf = GetPdfDocuments();  
    return File(pdf, &quot;application/pdf&quot;);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, you’ll want to add the button in your view to trigger this MVC action.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a class=&quot;btn btn-primary&quot;
   asp-controller=&quot;Files&quot;
   asp-action=&quot;Show&quot;
   target=&quot;_blank&quot;&amp;gt;
    Preview PDF
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it! Clicking the &lt;strong&gt;Preview&lt;/strong&gt; button will trigger your browser to open the file in a new tab. But you may be
asking yourself, “Why does this work?” Let’s look at the response headers of the HTTP request.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Length: 78127
Content-Type: application/pdf
Date: Wed, 06 Sep 2023 14:17:30 GMT
Server: Kestrel
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A client (web browser) uses the content type of &lt;code&gt;application/pdf&lt;/code&gt; to determine if a default viewing application is
associated with the MIME type. Since the PDF is a standard format, most modern browsers can render them in-app (sorry,
Adobe Acrobat Reader). The user can now view the file as if it were another tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: It’s essential to recognize that users can also change their preferences regarding how files are handled, so
this can behave differently based on an individual’s local setup.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What if you don’t want this behavior and want to force a download?&lt;/p&gt;

&lt;h2 id=&quot;downloading-a-pdf-file-in-the-browser&quot;&gt;Downloading a PDF File in the Browser&lt;/h2&gt;

&lt;p&gt;If you want to let folks download files rather than having the client open the file in the browser, it’s as simple as
adding another argument to the previous code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public IActionResult Download()  
{  
    var pdf = GetPdfDocuments();  
    return File(pdf, &quot;application/pdf&quot;, &quot;download.pdf&quot;);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, the button in your view is similar to the previous example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a class=&quot;btn btn-primary&quot;
   asp-controller=&quot;Files&quot;
   asp-action=&quot;Download&quot;&amp;gt;
    Download PDF
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, why does this download the PDF rather than preview the file?&lt;/p&gt;

&lt;p&gt;Let’s look at the HTTP response headers to see what’s different.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Disposition: attachment; filename=download.pdf; filename*=UTF-8&apos;&apos;download.pdf
Content-Length: 78109
Content-Type: application/pdf
Date: Wed, 06 Sep 2023 14:17:30 GMT
Server: Kestrel
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see a &lt;code&gt;Content-Disposition&lt;/code&gt; response header with the value of &lt;code&gt;attachment&lt;/code&gt; and a &lt;code&gt;filename&lt;/code&gt;. This tells the
browser that the server intends the client to download the file rather than attempt to render it as a document.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While the focus of this blog post was PDFs, this applies to any document type. If the user has a default application
that can preview a file, then excluding the filename will attempt to open and preview the document. For PDFs, most
browsers can render them in-app without additional applications. For downloading files, you only need to remember to
give the file a name.&lt;/p&gt;

&lt;p&gt;I hope this post was informative to you, and as always, thanks for sharing my posts with colleagues and friends. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 21 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/aspnet-core-pdf-previews-and-downloads</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/aspnet-core-pdf-previews-and-downloads</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>VestPocket: File-based Data Storage for AOT .NET Applications</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=oBad-MQaqdE&quot;&gt;As Zoolander villain Mugato&lt;/a&gt; might say if he were a .NET developer, &lt;em&gt;“Ahead of Time (AOT) compilation is so hot right now.”&lt;/em&gt; AOT is one of the focuses of the .NET 8 release, with a lot of attention given to high-performance scenarios. For the uninitiated, the act of AOT is compiling a higher-level language into a lower-level language for a better execution profile at runtime. In the case of .NET AOT, it’s targeting builds for specific environments to get near-native performance.&lt;/p&gt;

&lt;p&gt;While many folks will undoubtedly start looking at AOT as an option to squeeze more juice out of their apps, they may have to reconsider many of their dependencies that are not AOT compatible. In that dependency vacuum, a new class of libraries will emerge to offer developers a way forward.&lt;/p&gt;

&lt;p&gt;In today’s blog post, let’s check out VestPocket. VestPocket is a file-based “database” closer to a key-value store than a full-blown database. It aims to provide developers with an in-memory record storage option while having them persisted to disk.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-vestpocket&quot;&gt;What is VestPocket?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/keithwill/VestPocket&quot;&gt;VestPocket&lt;/a&gt; is a .NET library that allows developers to store entities in a single file. Records are serialized using &lt;code&gt;System.Text.Json&lt;/code&gt; and the newer AOT-compatible serialization source generators in .NET 7. The library is meant to give the developer a local database instance without the overhead of a database engine.&lt;/p&gt;

&lt;p&gt;Some use cases might involve:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Version and deploy application-specific data in a human-readable file.&lt;/li&gt;
  &lt;li&gt;Caching data locally in a single application instance.&lt;/li&gt;
  &lt;li&gt;As a proof-of-concept database for demos and samples.&lt;/li&gt;
  &lt;li&gt;You need more resilience than in-memory collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can get a solution up and running with a bit of setup. Let’s do that now!&lt;/p&gt;

&lt;h2 id=&quot;getting-started-with-vestpocket&quot;&gt;Getting Started with VestPocket&lt;/h2&gt;

&lt;p&gt;Before getting started, you’ll need to install the &lt;code&gt;VestPocket&lt;/code&gt; NuGet package. As mentioned in the previous section, VestPocket uses &lt;code&gt;System.Text.Json&lt;/code&gt; and source generators to serialize records into the file-based format. Let’s start by looking at setting up our entity models.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Json.Serialization;  
using VestPocket;  
  
namespace Vested;  
  
[JsonSerializable(typeof(Entity))]  
[JsonSourceGenerationOptions(WriteIndented = false)]  
public partial class DatabaseContext : JsonSerializerContext  
{  
}  
  
[JsonDerivedType(typeof(Entity), nameof(Entity))]  
[JsonDerivedType(typeof(Person), nameof(Person))]  
public record Entity(string Key, int Version, bool Deleted)  
    : IEntity  
{  
    public IEntity WithVersion(int version)  
        =&amp;gt; this with { Version = version };  
}  
  
public record Person(  
    string Key,  
    string Name,  
    int Age,  
    int Version = 0,  
    bool Deleted = false  
) : Entity(Key, Version, Deleted);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All your VestPocket entities will need a base &lt;code&gt;Entity&lt;/code&gt; type. This type is created within your application and must implement the &lt;code&gt;IEntity&lt;/code&gt; interface from VestPocket. Once you have a base record, you can begin implementing derived entities. In the previous code, I implemented a new &lt;code&gt;Person&lt;/code&gt; entity. Be sure to mark your &lt;code&gt;Entity&lt;/code&gt; instance with all derived entities using &lt;code&gt;JsonDerivedType&lt;/code&gt;. This attribute tells &lt;code&gt;System.Text.Json&lt;/code&gt; the derived types that the &lt;code&gt;JsonSerializerContext&lt;/code&gt; should be aware of when building serializers and deserializers to create for use at runtime. Finally, we set up the &lt;code&gt;DatabaseContext&lt;/code&gt; with serialization options and known entities. Again, since everything will derive from &lt;code&gt;Entity&lt;/code&gt;, we only need one &lt;code&gt;JsonSerializable&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Now, let’s write some code using our new data storage.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Vested;  
using VestPocket;  
  
var options = new VestPocketOptions { FilePath = &quot;test.vest&quot; };  
var store = new VestPocketStore&amp;lt;Entity&amp;gt;(DatabaseContext.Default.Entity, options);  
  
// open the database  
await store.OpenAsync(CancellationToken.None);  
  
var khalid =   
    store.Get&amp;lt;Person&amp;gt;(&quot;person/khalid&quot;) ??  
    new(&quot;person/khalid&quot;, &quot;Khalid Abuhakmeh&quot;, 40);  
  
var maarten =   
    store.Get&amp;lt;Person&amp;gt;(&quot;person/maarten&quot;) ??  
    new(&quot;person/maarten&quot;, &quot;Maarten Balliauw&quot;, 39);  
  
// will save a new version or increment version  
await store.Save(new Entity[] { khalid, maarten });  
  
// get all people  
var people = store.GetByPrefix&amp;lt;Person&amp;gt;(&quot;person/&quot;);  
  
foreach (var (_, name, age, _, _) in people)  
{  
    Console.WriteLine($&quot;{name} ({age})&quot;);  
}  
  
// maintenance (clean up previous versions)  
await store.ForceMaintenance();  
  
// close store (flush any pending writes)  
await store.Close(CancellationToken.None);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’ve used any .NET object-relation mapper, this style will likely not surprise you. Let’s break down the sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var options = new VestPocketOptions { FilePath = &quot;test.vest&quot; };  
var store = new VestPocketStore&amp;lt;Entity&amp;gt;(DatabaseContext.Default.Entity, options);  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A &lt;code&gt;VestPocketStore&lt;/code&gt; is your access method to your data storage. The constructor takes the &lt;code&gt;Entity&lt;/code&gt; serializer generated by &lt;code&gt;System.Text.Json&lt;/code&gt; and an instance of &lt;code&gt;VestPocketOptions&lt;/code&gt;. Stores are thread-safe, so you can share a single store instance across your application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// open the database  
await store.OpenAsync(CancellationToken.None);  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To create the file or access an existing file, the &lt;code&gt;OpenAsync&lt;/code&gt; method must be invoked.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var khalid =   
    store.Get&amp;lt;Person&amp;gt;(&quot;person/khalid&quot;) ??  
    new(&quot;person/khalid&quot;, &quot;Khalid Abuhakmeh&quot;, 40);  
  
var maarten =   
    store.Get&amp;lt;Person&amp;gt;(&quot;person/maarten&quot;) ??  
    new(&quot;person/maarten&quot;, &quot;Maarten Balliauw&quot;, 39);  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code may look weird, but for the sake of this sample, I check to see if the sample has already stored a previous version of our records. If so, we retrieve the existing element. Otherwise, we’ll create a new record in memory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// will save a new version or increment version  
await store.Save(new Entity[] { khalid, maarten });  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we attempt to store the records. It’s important to note that VestPocket is an append-only write system. So, you might have multiple versions of the same record. Here is the &lt;code&gt;test.vest&lt;/code&gt; file on disk.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{&quot;Creation&quot;:&quot;2023-09-05T13:20:35.044512-04:00&quot;,&quot;LastRewrite&quot;:&quot;2023-09-05T13:30:11.911718-04:00&quot;,&quot;CompressedEntities&quot;:null}  
{&quot;$type&quot;:&quot;Person&quot;,&quot;Name&quot;:&quot;Khalid Abuhakmeh&quot;,&quot;Age&quot;:40,&quot;Key&quot;:&quot;person/khalid&quot;,&quot;Version&quot;:3,&quot;Deleted&quot;:false}  
{&quot;$type&quot;:&quot;Person&quot;,&quot;Name&quot;:&quot;Maarten Balliauw&quot;,&quot;Age&quot;:39,&quot;Key&quot;:&quot;person/maarten&quot;,&quot;Version&quot;:3,&quot;Deleted&quot;:false}  
{&quot;$type&quot;:&quot;Person&quot;,&quot;Name&quot;:&quot;Khalid Abuhakmeh&quot;,&quot;Age&quot;:40,&quot;Key&quot;:&quot;person/khalid&quot;,&quot;Version&quot;:4,&quot;Deleted&quot;:false}  
{&quot;$type&quot;:&quot;Person&quot;,&quot;Name&quot;:&quot;Maarten Balliauw&quot;,&quot;Age&quot;:39,&quot;Key&quot;:&quot;person/maarten&quot;,&quot;Version&quot;:4,&quot;Deleted&quot;:false}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As the previous code shows, you can always retrieve records by a specific key, but you can filter the results down based on key prefixes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// get all people  
var people = store.GetByPrefix&amp;lt;Person&amp;gt;(&quot;person/&quot;);  
  
foreach (var (_, name, age, _, _) in people)  
{  
    Console.WriteLine($&quot;{name} ({age})&quot;);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You may also want to “clean up” the database of old versions eventually. This is where the call to &lt;code&gt;ForceMaintenance&lt;/code&gt; helps. It removes all but the latest version of an entity.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// maintenance (clean up previous versions)  
await store.ForceMaintenance();  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, before our application exits, we want to ensure we’ve flushed all records to disk. We can do that by calling &lt;code&gt;Close&lt;/code&gt; on our store instance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// close store (flush any pending writes)  
await store.Close(CancellationToken.None);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There, you have it. A simple one-file usage of VestPocket.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With AOT on the horizon, it’s nice to see folks experimenting with it and providing the community with packages. VestPocket is a file-based data storage mechanism with an &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/extensible-storage-engine/extensible-storage-engine-managed-reference&quot;&gt;ESENT vibe&lt;/a&gt;, and that’s pretty neat. While still in the experimental phase, I can see it being helpful in the use cases the author describes. Head over to &lt;a href=&quot;https://github.com/keithwill/VestPocket&quot;&gt;the VestPocket GitHub repository&lt;/a&gt; and give it a star.&lt;/p&gt;

&lt;p&gt;As always, thank you for reading and sharing my posts with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 14 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/vestpocket-file-based-data-storage-for-aot-dotnet-applications</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/vestpocket-file-based-data-storage-for-aot-dotnet-applications</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>MoonSharp - Running Lua Scripts in .NET</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://www.lua.org/about.html&quot;&gt;Lua&lt;/a&gt; is a scripting language most famously known for powering Blizzard’s World of Warcraft but was designed to be a general-purpose means of building robust, efficient, and lightweight solutions. Lua was created in 1993 (30 years ago!) and has since been popular among developers across all ecosystems. Lua is an excellent choice for folks because it is fast, portable, embeddable, small, and Free under an MIT license.&lt;/p&gt;

&lt;p&gt;If you’ve ever dreamed about building extensibility into your applications, Lua is an excellent choice, as you can allow consumers to build scripts that work within your .NET host application. In this post, we’ll walk through the straightforward steps to add Lua support to your .NET applications, how you might invoke Lua scripts, and how you might let Lua scripts call your .NET methods.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;getting-started-with-moonsharp&quot;&gt;Getting Started with MoonSharp&lt;/h2&gt;

&lt;p&gt;In a .NET console application, start by installing the &lt;code&gt;MoonSharp&lt;/code&gt; NuGet package.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;dotnet add package MoonSharp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also add the following &lt;code&gt;ItemGroup&lt;/code&gt; to your .NET project file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;  
  &amp;lt;PackageReference Include=&quot;MoonSharp&quot; Version=&quot;2.0.0&quot; /&amp;gt;  
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that, you should be ready to start writing your first Lua script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As a bonus, if you’re using &lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider&lt;/a&gt; you’ll get Lua syntax highlighting with the language injections feature.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;Program.cs&lt;/code&gt; file, add the following code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MoonSharp.Interpreter;  
  
// language=lua  
var lua =  
  &quot;&quot;&quot;  
  print(&quot;Hello, Lua&quot;)  
  &quot;&quot;&quot;;  
  
Script.DefaultOptions.DebugPrint = Console.WriteLine;  
Script.RunString(lua);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see the following output in your console when you run your Console application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Hello, Lua
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Setting the &lt;code&gt;DebugPrint&lt;/code&gt; property is necessary to allow MoonSharp to redirect print output somewhere. We chose the console in this case, but it could be directed to a &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;Stream&lt;/code&gt;, or whatever.&lt;/p&gt;
&lt;h2 id=&quot;invoke-a-lua-function-from-c&quot;&gt;Invoke a Lua Function from C#&lt;/h2&gt;

&lt;p&gt;Doing a &lt;code&gt;print&lt;/code&gt; call is fun, but we can be more practical. Let’s step it up by invoking a Lua &lt;code&gt;add&lt;/code&gt; method that takes two integer arguments.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MoonSharp.Interpreter;  
  
Script.DefaultOptions.DebugPrint = Console.WriteLine;  
  
// language=lua  
var lua =  
  &quot;&quot;&quot;  
  function add(x, y)    
      return x + y  
  end  
  &quot;&quot;&quot;;  
  
var script = new Script();  
// loads and executes script  
script.DoString(lua);  
// call our global method  
DynValue value = script.Call(script.Globals[&quot;add&quot;], 1, 1);  
  
Console.WriteLine($&quot;1 + 1 is {value.Number}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we load a new function of &lt;code&gt;add&lt;/code&gt; that takes two number arguments. Remember, Lua is dynamically typed, so you won’t see any type declarations. We create a &lt;code&gt;script&lt;/code&gt; variable to reuse the context of our script, which now holds a global add function. We can use the script variable from here to invoke our global function and the necessary arguments. The &lt;code&gt;DynValue&lt;/code&gt; is a dynamic result, but there are helper properties you can use to type the result to a known .NET type. In this case, we’ll use the &lt;code&gt;Number&lt;/code&gt; property to get an integer value. Executing our application, we get the console output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1 + 1 is 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What if we want a Lua script to call our .NET application?&lt;/p&gt;

&lt;h2 id=&quot;invoking-a-c-method-from-a-lua-script&quot;&gt;Invoking a C# Method from a Lua Script&lt;/h2&gt;

&lt;p&gt;MoonSharp allows you to inject elements into the global script context. In this section, we’ll provide our Lua script with an add method and do the addition in the scope of a C# code block.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MoonSharp.Interpreter;  
  
Script.DefaultOptions.DebugPrint = Console.WriteLine;  
  
// language=lua  
var lua =  
  &quot;&quot;&quot;  
  local result = add(1,1)  
  local output = string.format(&quot;1 + 1 is %s&quot;, result)  
  print(output)  
  &quot;&quot;&quot;;  
  
var script = new Script();  
  
int add(int x, int y)  
{  
  Console.WriteLine(&quot;Yep, I&apos;m .NET baby!&quot;);  
  return x + y;  
}  
  
// load our C# method into global  
script.Globals[nameof(add)] = add;   
// loads and executes script  
script.DoString(lua);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We pass the C# local function of &lt;code&gt;add&lt;/code&gt; as a &lt;code&gt;Func&amp;lt;int,int,int&amp;gt;&lt;/code&gt; to Lua. This allows Lua scripts to invoke the global method. Running the code above returns the following result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Yep, I&apos;m .NET baby!
1 + 1 is 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We’ve only scratched the surface of what MoonSharp has to offer with Lua, but with these three demonstrations, you can see that the interoperability possibilities are through the roof. Leveraging MoonSharp you can build extensibility into your applications using a battle-hardened scripting language.&lt;/p&gt;

&lt;p&gt;If you want to learn more about &lt;a href=&quot;https://www.moonsharp.org/&quot;&gt;MoonSharp, visit the official site to see more samples and to read the official documentation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/moonsharp-running-lua-scripts-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/moonsharp-running-lua-scripts-in-dotnet</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>What Should I Dispose with .NET Database Connections?</title>
        <description>&lt;p&gt;When working with “expensive” resources, it is essential to call the &lt;code&gt;Dispose&lt;/code&gt; method to tell .NET’s garbage collector that it’s time to clean up the instance and all its associated baggage. Disposing of instances is most important when dealing with finite resources on the hot path of your codebase, and for most .NET developers, the most crucial resource is a database connection. Your app is done for if you run out of database connections.&lt;/p&gt;

&lt;p&gt;With database connections, we also have a supporting cast of commands and readers, all of which can be disposed of as well. This leads to an interesting question: &lt;strong&gt;&lt;em&gt;“Do you HAVE TO dispose everything?”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore the &lt;code&gt;Microsoft.Data.Sqlite&lt;/code&gt; implementations of &lt;code&gt;DbConnection&lt;/code&gt;, &lt;code&gt;DbCommand&lt;/code&gt;, and &lt;code&gt;DbDataReader&lt;/code&gt; and see what happens when we call &lt;code&gt;Dispose&lt;/code&gt; on each type.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-data-access-code&quot;&gt;The Data Access Code&lt;/h2&gt;

&lt;p&gt;When working with ADO.NET, you’ll likely be using a &lt;code&gt;Microsoft.Data.*&lt;/code&gt; package or a community library like &lt;code&gt;Npgsql&lt;/code&gt;. Each library implements a database-specific version of &lt;code&gt;DbConnection&lt;/code&gt;, &lt;code&gt;DbCommand&lt;/code&gt;, &lt;code&gt;DbReader&lt;/code&gt;, and other intrinsics. Let’s write a simple application that opens a connection, creates a command, and then reads the results.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Data.Sqlite;  
  
await using SqliteConnection connection = new(&quot;Data Source=test.sqlite&quot;);  
await connection.OpenAsync();  
  
await using SqliteCommand command = connection.CreateCommand();  
command.CommandText = &quot;SELECT * FROM sqlite_master&quot;;  
  
await using SqliteDataReader reader = command.ExecuteReader();  
Console.WriteLine($&quot;Has Rows? {reader.HasRows}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You may notice a few things happening in the previous code.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;All implementations implement &lt;code&gt;IDisposable&lt;/code&gt;, but more specifically &lt;code&gt;IAsyncDisposable&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;We can use scope-based disposal, which disposed of our instances as soon as they fall out of scope. The use of &lt;code&gt;await using&lt;/code&gt; allows us to do that.&lt;/li&gt;
  &lt;li&gt;All instances are disposed of, but do we need it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the following sections, we’ll see what each dispose of and if we need to dispose of all instances in the code sample.&lt;/p&gt;
&lt;h2 id=&quot;disposing-a-sqliteconnection&quot;&gt;Disposing a SqliteConnection&lt;/h2&gt;

&lt;p&gt;What does disposing of an instance of &lt;code&gt;SqliteConnection&lt;/code&gt; entail? Looking through the codebase using my trusty decompiler, I found that calling dispose does a lot.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;protected override void Dispose(bool disposing)  
{  
    if (disposing)  
    {        
        Close();  
    }  
    base.Dispose(disposing);  
}

public override void Close()  
{  
    if (State != ConnectionState.Open)  
    {        
        return;  
    }
      
    Transaction?.Dispose();  
  
    for (var i = _commands.Count - 1; i &amp;gt;= 0; i--)  
    {        
        var reference = _commands[i];  
        if (reference.TryGetTarget(out var command))  
        {            
            // NB: Calls RemoveCommand()  
            command.Dispose();  
        }        
        else  
        {  
            _commands.RemoveAt(i);  
        }    
    }  
    Debug.Assert(_commands.Count == 0);  
  
    _innerConnection!.Close();  
    _innerConnection = null;  
  
    _state = ConnectionState.Closed;  
    OnStateChange(_fromOpenToClosedEventArgs);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
  &lt;li&gt;It closes the current connection and sets the state to closed.&lt;/li&gt;
  &lt;li&gt;It disposes of any active transactions to the database.&lt;/li&gt;
  &lt;li&gt;It also disposes of any &lt;code&gt;DbCommand&lt;/code&gt; instances associated with the connection and removes them from being tracked.&lt;/li&gt;
  &lt;li&gt;If there are any inner connections, they get disposed of as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hmm… commands get disposed of. Well, what does that do?&lt;/p&gt;

&lt;h2 id=&quot;disposing-a-sqlitecommand&quot;&gt;Disposing a SqliteCommand&lt;/h2&gt;

&lt;p&gt;No surprise, but disposing of a &lt;code&gt;SqliteCommand&lt;/code&gt; does a lot too! Let’s take a look at the implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;protected override void Dispose(bool disposing)  
{  
    DisposePreparedStatements(disposing);  
  
    if (disposing)  
    {        
        _connection?.RemoveCommand(this);  
    }  
    base.Dispose(disposing);  
}

private void DisposePreparedStatements(bool disposing = true)  
{  
    if (disposing &amp;amp;&amp;amp; DataReader != null)  
    {        
        DataReader.Dispose();  
        DataReader = null;  
    }  
    if (_preparedStatements != null)  
    {        
        foreach ((var stmt, _) in _preparedStatements)  
        {            
            stmt.Dispose();  
        }  
        _preparedStatements.Clear();  
    }  
    _prepared = false;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
  &lt;li&gt;The command is removed from the associated connection&lt;/li&gt;
  &lt;li&gt;Any reader associated with the command is disposed.&lt;/li&gt;
  &lt;li&gt;All statements associated with the command are disposed of and cleared from a tracking collection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Interestingly, again, disposing of the command disposes the reader. Let’s keep going. What does that do?&lt;/p&gt;

&lt;h2 id=&quot;disposing-a-sqlitedatareader&quot;&gt;Disposing a SqliteDataReader&lt;/h2&gt;

&lt;p&gt;We’re almost to the end. What happens when a &lt;code&gt;SqliteDataReader&lt;/code&gt; gets disposed?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;protected override void Dispose(bool disposing)  
{  
    if (!disposing || _closed)  
    {        
        return;  
    }  
    _command.DataReader = null;  
  
    _record?.Dispose();  
    _record = null;  
  
    if (_stmtEnumerator != null)  
    {        
        try  
        {  
            while (NextResult())  
            {            
            }        
        }        
        catch  
        {  
        }    
    }  
    _stmtEnumerator?.Dispose();  
  
    _closed = true;  
  
    if (_closeConnection)  
    {        
        _command.Connection!.Close();  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, disposing of the reader disposes of all the record instances currently part of the reader. The method will also disconnect from the command it is associated with. Also, in this case, the reader will close the connection if a boolean is set to true.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Following the chain of calls, calling &lt;code&gt;Dispose&lt;/code&gt; on the &lt;code&gt;SqliteConnection&lt;/code&gt; should be enough for most folks to reclaim the resources allocated by the initial code. That said, if you want to reclaim your resources “faster”, you can undoubtedly call the &lt;code&gt;Dispose&lt;/code&gt; methods as soon as you’re done with the resource. Generally, I recommend calling dispose on derived instances from &lt;code&gt;SqliteConnection&lt;/code&gt; if you use object-pooling, where the root instance is long-lived. This is a common practice in ORMs, which can help improve performance. Finally, if you’re using a dependency injection library, it already handles object disposal automatically for you. As always, check your code, use the decompiler, and learn how stuff works.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts with friends and colleagues. Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 31 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/what-should-i-dispose-with-dotnet-database-connections</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/what-should-i-dispose-with-dotnet-database-connections</guid>
        
        <category>dotnet</category>
        
        <category>database</category>
        
        
      </item>
    
      <item>
        <title>Global Endpoint Filters with ASP.NET Core Minimal APIs</title>
        <description>&lt;p&gt;The ASP.NET Core technology stack works on the pipeline concept. A user request travels through the pipeline, where you have opportunities to handle the request in various forms. The approach to enhancing the pipeline in ASP.NET Core has been a mixture of Middleware and paradigm-specific filters. Filters for ASP.NET Core MVC give you MVC-specific idioms to work with, while Middleware typically works with the rawest elements of an &lt;code&gt;HttpContext&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;/aspnet-core-minimal-api-endpoint-filters&quot;&gt;With Minimal APIs, you can implement the &lt;code&gt;IEndpointFilter&lt;/code&gt; interface I wrote about previously&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post, we’ll see a technique to apply the &lt;code&gt;IEndpointFilter&lt;/code&gt; to all endpoints, similar to ASP.NET Core MVC’s global filters. As a bonus, it’s pretty straightforward.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-not-middleware&quot;&gt;Why not Middleware?&lt;/h2&gt;

&lt;p&gt;Middleware in ASP.NET Core is designed to operate as a gate to incoming HTTP requests and outgoing HTTP responses. You could use the &lt;code&gt;IMiddleware&lt;/code&gt; interface to process the request, but you’ll quickly find out you’re working with lower-level intrinsics than you might want. Let’s take a look at an implementation of a new Middleware.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class MyMiddleware: IMiddleware  
{  
    public Task InvokeAsync(HttpContext context, RequestDelegate next)  
    {        
        throw new NotImplementedException();  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll quickly notice the use of &lt;code&gt;HttpContext&lt;/code&gt; and the &lt;code&gt;RequestDelegate&lt;/code&gt; types. These types can give you access to elements of the request pipeline you might need, but the accessing code can be verbose and opaque. In other words, you’ll quickly find your Middleware code exploding in complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Middleware is an excellent tool for applying similar functionality across all ASP.NET Core development paradigms, including MVC, Razor Pages, Minimal APIs, and Blazor.&lt;/strong&gt; To offer that breadth, middleware implementations must work at the lowest abstractions.&lt;/p&gt;

&lt;p&gt;On the other hand, the &lt;code&gt;IEndpointFilter&lt;/code&gt; is explicitly designed to work with the latest concept of Endpoints, which includes Minimal APIs, MVC, and Razor Pages. Endpoints generally focus on inputs and outputs, with the pipeline responsible for executing those results. It’s easier to see this in the implementation of a filter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class ScreamingFilter: IEndpointFilter  
{  
    public async ValueTask&amp;lt;object?&amp;gt; InvokeAsync(  
        EndpointFilterInvocationContext context,  
        EndpointFilterDelegate next)  
    {        
        var result = await next(context);  
        return result is string s   
            ? $&quot;{s}!!!!&quot;   
            : result;  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rather than working with &lt;code&gt;HttpContext&lt;/code&gt;, we are working with the return value of our endpoint. That allows us to deal with objects and their properties. This opens up a world of possibilities regarding object inspection and enrichment that can be difficult to do with middleware.&lt;/p&gt;

&lt;p&gt;OK, enough theory. Let’s get to Global Endpoint Filters for Minimal APIs.&lt;/p&gt;

&lt;h2 id=&quot;the-one-trick-that-makes-it-possible&quot;&gt;The One Trick That Makes It Possible&lt;/h2&gt;

&lt;p&gt;First of all, and I’ll be the first to admit it, this technique can seem “simple” on the surface, but it works surprisingly well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You need a global’ Map’ group to get Global Endpoint Filters for Minimal APIs working.&lt;/strong&gt; Let’s see this in action.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);  
  
var app = builder.Build();  

// the magic 🪄
var global = app  
    .MapGroup(string.Empty)  
    .AddEndpointFilter&amp;lt;ScreamingFilter&amp;gt;();  
  
global.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Hello World&quot;);  
global.MapGet(&quot;/hi&quot;, () =&amp;gt; &quot;Hi&quot;);  
global.MapGroup(&quot;/what&quot;).MapGet(&quot;/now&quot;, () =&amp;gt; &quot;🤷&quot;);  
  
app.Run();  
  
public class ScreamingFilter: IEndpointFilter  
{  
    public async ValueTask&amp;lt;object?&amp;gt; InvokeAsync(  
        EndpointFilterInvocationContext context,  
        EndpointFilterDelegate next)  
    {        
        var result = await next(context);  
        return result is string s   
            ? $&quot;{s}!!!!&quot;   
            : result;  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The trick is to register all endpoints off of the root &lt;code&gt;MapGroup&lt;/code&gt;. Each additional endpoint will now inherit the filters of the group. Since the &lt;code&gt;global&lt;/code&gt; group has no route prefix, it doesn’t affect any paths of registered endpoints. The explicit type of &lt;code&gt;global&lt;/code&gt; is &lt;code&gt;RouteGroupBuilder&lt;/code&gt;, which implements &lt;code&gt;IEndpointRouteBuilder&lt;/code&gt; and &lt;code&gt;IEndpointConventionBuilder&lt;/code&gt;, which should give you access to the same functionality as registering a regular endpoint, including having additional sub-groups.&lt;/p&gt;

&lt;p&gt;Now, you have what are essentially global endpoint filters for all your minimal API endpoints. Pretty cool! Note that endpoint execution ordering will still apply. All “global” endpoint filters will execute first, then any filters applied directly to the endpoints.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading my blog posts and for sharing my posts with friends and colleagues. Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 24 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/global-endpoint-filters-with-aspnet-core-minimal-apis</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/global-endpoint-filters-with-aspnet-core-minimal-apis</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>RazorSlices - Razor Views with ASP.NET Core Minimal APIs</title>
        <description>&lt;p&gt;With .NET 8 on the horizon, Minimal APIs continues to grow its offerings, slowly providing a similar feature set to the frameworks before, including ASP.NET Core MVC and Razor Pages. I was surprised when someone in the community (👋 Hi &lt;a href=&quot;https://github.com/jchannon&quot;&gt;Johnathan Channon&lt;/a&gt;) pointed me to a fascinating &lt;a href=&quot;https://github.com/DamianEdwards/RazorSlices#no-intention-to-support&quot;&gt;RazorSlices&lt;/a&gt; project. RazorSlices is written by &lt;a href=&quot;https://github.com/DamianEdwards/RazorSlices/commits?author=DamianEdwards&quot;&gt;Damian Edwards&lt;/a&gt;, an ASP.NET Core team member with a history of working with the Razor view engine. His goal is to bring Razor functionality to Minimal API adopters in a similar way that ASP.NET Core MVC, Razor Pages, and Blazor users enjoy today.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to set up &lt;a href=&quot;https://github.com/DamianEdwards/RazorSlices#no-intention-to-support&quot;&gt;RazorSlices&lt;/a&gt; in your ASP.NET Core applications and think about the pros and cons of its usage.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;getting-started-with-razorslices&quot;&gt;Getting Started with RazorSlices&lt;/h2&gt;

&lt;p&gt;In a Minimal API project, start by installing the RazorSlices package. You can do this by using the &lt;code&gt;dotnet add package RazorSlices&lt;/code&gt; command or by adding the appropriate &lt;code&gt;PackageReference&lt;/code&gt; in your &lt;code&gt;.csproj&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PackageReference Include=&quot;RazorSlices&quot; Version=&quot;0.7.0&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, create a folder at the root of your ASP.NET Core application. It can be named anything you like. I chose &lt;code&gt;Slices&lt;/code&gt; as it was what the documentation recommended. This directory is where you’ll place all your Razor views to be used in your Minimal API endpoints.&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;Slices&lt;/code&gt; folder, create a new file named &lt;code&gt;_ViewImports.cshtml&lt;/code&gt;. The view imports file allows you to create a shared context for all views within the folder, including namespaces, base classes, and tag helpers. Here’s the contents of my file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@inherits RazorSliceHttpResult  
  
@using System.Globalization;  
@using Microsoft.AspNetCore.Razor;  
@using Microsoft.AspNetCore.Http.HttpResults;  
  
@tagHelperPrefix __disable_tagHelpers__:  
@removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice two strange things when looking at this file:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;code&gt;@inherits&lt;/code&gt; value is of &lt;code&gt;RazorSliceHttpResult&lt;/code&gt; to work with the &lt;code&gt;IResult&lt;/code&gt; type used my Minimal APIs.&lt;/li&gt;
  &lt;li&gt;Tag helpers are removed and obfuscated. That’s because they’re not supported in this model. Only expect to port a Razor Pages implementation over to RazorSlices by making some modifications or concessions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, you’ll want to create a new &lt;code&gt;Hello.cshtml&lt;/code&gt; view in the &lt;code&gt;Slices&lt;/code&gt; folder.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@inherits RazorSliceHttpResult&amp;lt;DateTime&amp;gt;  
&amp;lt;!DOCTYPE html&amp;gt;  
&amp;lt;html lang=&quot;en&quot;&amp;gt;  
&amp;lt;head&amp;gt;  
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;  
    &amp;lt;title&amp;gt;Hello from Razor Slices!&amp;lt;/title&amp;gt;  
&amp;lt;/head&amp;gt;  
&amp;lt;body&amp;gt;  
&amp;lt;p&amp;gt;  
    Hello from Razor Slices! The time is @Model  
&amp;lt;/p&amp;gt;  
&amp;lt;/body&amp;gt;  
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the view also uses the &lt;code&gt;@inherit&lt;/code&gt; attribute, but this time uses a generic type definition. The generic type argument is the type of the &lt;code&gt;@Model&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Finally, you’ll want to use the view in your Minimal API endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);  
var app = builder.Build();  
  
app.MapGet(&quot;/&quot;, () =&amp;gt;  
    Results.Extensions.RazorSlice(&quot;/Slices/Hello.cshtml&quot;, DateTime.Now));  
  
app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that’s it! You are now rendering Razor views through your Minimal API endpoint.&lt;/p&gt;

&lt;p&gt;For folks using JetBrains tooling, go a little extra and install &lt;strong&gt;JetBrains.Annotations&lt;/strong&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;dotnet add package JetBrains.Annotations
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, modify your code to look like the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using JetBrains.Annotations;  
  
var builder = WebApplication.CreateBuilder(args);  
var app = builder.Build();  
  
app.MapGet(&quot;/&quot;, () =&amp;gt;  
    Slice(&quot;/Slices/Hello.cshtml&quot;, DateTime.Now));  
  
app.Run();  
  
IResult Slice&amp;lt;T&amp;gt;([AspMvcView]string viewPath, T model)  
    =&amp;gt; Results.Extensions.RazorSlice(viewPath, model);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The benefit here is you can now &lt;kbd&gt;Ctrl&lt;/kbd&gt; + Click through to your view right from the C# code. That should help your productivity. This works because you need to reference RazorSlice views by the absolute path, and JetBrains Rider and ReSharper undertand that behavior. Pretty awesome, right?&lt;/p&gt;

&lt;h2 id=&quot;the-pros-of-razorslices&quot;&gt;The Pros of RazorSlices&lt;/h2&gt;

&lt;p&gt;The most obvious benefit here is that you can now use Razor to generate HTML results in your Minimal API endpoints. I might be biased, but I love the Razor syntax and its benefits to the web development experience.&lt;/p&gt;

&lt;p&gt;Another significant benefit is your Razor views can also use the &lt;code&gt;@inject&lt;/code&gt; attribute, giving you access to dependencies in the HTML rendering process.&lt;/p&gt;

&lt;p&gt;If performance is a concern of yours, there is a &lt;code&gt;SliceFactory&lt;/code&gt;, that can help reduce the cost associated with looking up views. This can be an easy win for folks looking to eek out more performance. Speaking of performance, there are plans to add Ahead of Time (AOT) support.&lt;/p&gt;

&lt;h2 id=&quot;the-cons-of-razorslices&quot;&gt;The Cons of RazorSlices&lt;/h2&gt;

&lt;p&gt;Let’s talk about the drawbacks of using RazorSlices, because there are a few.&lt;/p&gt;

&lt;p&gt;As mentioned, if you’re looking for a one-to-one replacement for MVC or Razor Pages, you will be disappointed. It’s meant to be something other than a drop-in replacement for either approach. This is evident when using features like TagHelpers or View Components.&lt;/p&gt;

&lt;p&gt;The library has no current support for partial views, making view composition and componentization impossible. It may find its way into the package but is currently unavailable. This includes the view infrastructure associated with MVC, like layouts and layout sections. As I said previously, this is not a drop-in replacement.&lt;/p&gt;

&lt;p&gt;A new paradigm means leaving behind the past paradigm. If you depend on third-party Razor libraries, they may not work in this current iteration.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;RazorSlices is worth checking out if you’re looking for a way to render HTML one step above string interpolation in your API endpoints. It provides the basics of what you love about Razor syntax, including expressions, control structures, looping, and code blocks. For most, that’s going to be enough to accomplish any goal. That said, if you’re looking for an ASP.NET Core MVC replacement, this library is far from being that, but that’s OK.&lt;/p&gt;

&lt;p&gt;Check out the library at &lt;a href=&quot;https://github.com/DamianEdwards/RazorSlices&quot;&gt;RazorSlices&lt;/a&gt; and let me know your thoughts. As always, thanks for reading and sharing my blog posts.&lt;/p&gt;

</description>
        <pubDate>Tue, 17 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/razorslices-razor-views-with-aspnet-core-minimal-apis</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/razorslices-razor-views-with-aspnet-core-minimal-apis</guid>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>How To Use Embedded Resources in .NET</title>
        <description>&lt;p&gt;While code is inarguably the bedrock of any software application, it’s not the only thing necessary to deliver a user experience. Whether you’re building a website, desktop application, or mobile app, you’ll likely need non-code assets. These assets include images, videos, third-party file formats, and more. Additionally, you should include localization values to support a variety of languages and grow your user base.&lt;/p&gt;

&lt;p&gt;This post will explore embedded resources in .NET and point to some material I’ve written for JetBrains about localizing your ASP.NET applications.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;embedded-resources&quot;&gt;Embedded Resources&lt;/h2&gt;

&lt;p&gt;An embedded resource is any file you want to include in your final built assembly. This can include anything from text files to binary formats like images or videos. Embedded resources use the &lt;code&gt;EmbeddedResource&lt;/code&gt; MSBuild element, which the compiler reads to transform project assets into binary embedded in your assemblies. Here are a few examples.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;  
  &amp;lt;EmbeddedResource Include=&quot;Embedded\test.txt&quot; /&amp;gt;  
  &amp;lt;None Remove=&quot;Embedded\person.json&quot; /&amp;gt;  
  &amp;lt;EmbeddedResource Include=&quot;Embedded\person.json&quot; /&amp;gt;  
  &amp;lt;EmbeddedResource Update=&quot;Embedded\Values.resx&quot;&amp;gt;  
    &amp;lt;Generator&amp;gt;ResXFileCodeGenerator&amp;lt;/Generator&amp;gt;  
    &amp;lt;LastGenOutput&amp;gt;Values.Designer.cs&amp;lt;/LastGenOutput&amp;gt;  
  &amp;lt;/EmbeddedResource&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once an asset is embedded, it is given a unique name in the resource manifest, which is typically similar to its file path but is overridable.&lt;/p&gt;

&lt;p&gt;Remember, assets are stored within the &lt;code&gt;Assembly&lt;/code&gt;, which means you must know which assembly has your resources to get the names from the manifest. Here is an example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var names =   
	System  
	.Reflection  
	.Assembly  
	.GetExecutingAssembly()  
	.GetManifestResourceNames();  
  
foreach (var name in names)  
{  
    Console.WriteLine(name);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Combined with our &lt;code&gt;ItemGroup&lt;/code&gt; from above, we’d get the following output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;BedTime.Embedded.Values.resources
BedTime.Embedded.test.txt
BedTime.Embedded.person.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You may have also noticed the use of &lt;code&gt;ResXFileCodeGenerator&lt;/code&gt;. The &lt;code&gt;Resx&lt;/code&gt; file format is a unique format used by .NET applications to store mostly &lt;code&gt;string&lt;/code&gt; values, but it can also be adapted to store binary formats like images in &lt;code&gt;base64&lt;/code&gt; strings. I don’t recommend it, but it’s possible.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.resx&lt;/code&gt; format is best suited for localization, &lt;a href=&quot;https://www.jetbrains.com/dotnet/guide/tutorials/localization/&quot;&gt;which I wrote about previously for JetBrains here. Check it out.&lt;/a&gt; It also generates a C# class for accessing values for straightforward usage. The format is also used by many of the features in .NET, including ASP.NET Core.&lt;/p&gt;

&lt;h2 id=&quot;accessing-embedded-resources-from-c&quot;&gt;Accessing Embedded Resources from C#&lt;/h2&gt;

&lt;p&gt;I recommend folks access embedded resources by writing &lt;code&gt;static&lt;/code&gt; wrapper classes that formalize the process of accessing assembly artifacts. let’s look at how we might access one of the files from the previous section, and then we’ll create the wrapper class for all resources.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var info = Assembly.GetExecutingAssembly().GetName();  
var name = info.Name;  
using var stream = Assembly  
    .GetExecutingAssembly()  
    .GetManifestResourceStream($&quot;{name}.Embedded.test.txt&quot;)!;  
using var streamReader = new StreamReader(stream, Encoding.UTF8);  
return streamReader.ReadToEnd();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Resource names will typically follow this convention &lt;code&gt;(Assembly Name).(Folders).(Filename)&lt;/code&gt; unless an explicit name exists. You can also use the &lt;code&gt;GetManifestResourceNames&lt;/code&gt; method to find a resource name if you can’t figure it out by convention.&lt;/p&gt;

&lt;p&gt;Now, let’s wrap all our resources in a static class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Reflection;
using System.Text;
using System.Text.Json;

namespace BedTime.Embedded;

public static class Resources
{
    public static class Embedded
    {
        public static string TestTxt
        {
            get
            {
                var info = Assembly.GetExecutingAssembly().GetName();
                var name = info.Name;
                using var stream = Assembly
                    .GetExecutingAssembly()
                    .GetManifestResourceStream($&quot;{name}.Embedded.test.txt&quot;)!;
                using var streamReader = new StreamReader(stream, Encoding.UTF8);
                return streamReader.ReadToEnd();
            }
        }

        public static Person Person
        {
            get
            {
                var info = Assembly.GetExecutingAssembly().GetName();
                var name = info.Name;
                using var stream = Assembly
                    .GetExecutingAssembly()
                    .GetManifestResourceStream($&quot;{name}.Embedded.person.json&quot;)!;
                return JsonSerializer.Deserialize&amp;lt;Person&amp;gt;(stream)!;
            }
        }
    }
}

public record Person(string Name, string[] Hobbies)
{
    public override string ToString()
    {
        return $&quot;{Name} likes {Hobbies.ToOxfordComma()}&quot;;
    }
};

public static class EnumerableExtensions
{
    public static string ToOxfordComma(this string[]? items)
    {
        var result = items?.Length switch
        {
            // three or more items
            &amp;gt;=3 =&amp;gt; $&quot;{string.Join(&quot;, &quot;, items[..^1])}, and {items[^1]}&quot;,
            // 1 item or 2 items
            not null =&amp;gt; string.Join(&quot; and &quot;, items),
            // null
            _ =&amp;gt; string.Empty
        };

        return result;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see why I recommend this route. You have more control over how you read values from the assembly and how to transform them into something useful. In the case of &lt;code&gt;Person&lt;/code&gt;, it’s a JSON file that we ultimately want to turn into an instance of a class. It’s also much nicer to use in your code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Console.WriteLine(Resources.Embedded.TestTxt);  
Console.WriteLine(Resources.Embedded.Person);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also add caching of elements to reduce resource-intensive actions like serialization and deserialization.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Embedded resources are a nice feature of the .NET programming stack and can be used to deliver application-critical assets bundled alongside your code. This reduces the need to read files from disk or deal with network calls to retrieve assets. This will increase the size of your assemblies, so use this approach sparingly and with caution. I also recommend hand-writing your embedded resource access to give you more granular control over the final result and to reduce conversion noise in your more critical code.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and thanks, as always, for reading.&lt;/p&gt;
</description>
        <pubDate>Tue, 10 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-embedded-resources-in-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-embedded-resources-in-dotnet</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>How To Display .NET Collections with the Oxford Comma</title>
        <description>&lt;p&gt;Taking a .NET collection and displaying the items in a human-readable format is something we all ultimately have to tackle in our applications. While we could spit out values uniformly separated by a character, that’s a very uncivilized approach. I’ll go as far as to say that the comma (,) and the use of “and” separates us from the animals. The peak of human evolution is the &lt;a href=&quot;https://www.grammarbook.com/blog/commas/oxford-comma/&quot;&gt;Oxford Comma&lt;/a&gt;, and it’s all been downhill from that moment.&lt;/p&gt;

&lt;p&gt;In this short post, we’ll see how to take a .NET collection and transform it into an Oxford Comma sentence using pattern matching.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-oxford-comma-is-life&quot;&gt;The Oxford Comma is Life&lt;/h2&gt;

&lt;p&gt;For those unfamiliar with the Oxford Comma rule, it’s a grammatical rule that says a final comma can be used in a series. For example, consider the following two sentences:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;How Harry Reid, a terrorist interrogator and the 
singer from Blink-182 took UFOs mainstream.

How Harry Reid, a terrorist interrogator, and the
singer from Blink-182 took UFOs mainstream.
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;I am visiting California to see my friends, Mickey Mouse and Dr. Dre.

I am visiting California to see my friends, Mickey Mouse, and Dr Dre.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These two sentences’ meanings change entirely due to a well-placed comma.&lt;/p&gt;

&lt;p&gt;When displaying values in code, you may want to format it for your users naturally, and picking the Oxford comma is the most natural form.&lt;/p&gt;

&lt;p&gt;Let’s see what tests for an Oxford Comma extension might look like.&lt;/p&gt;

&lt;h2 id=&quot;oxford-comma-tests-and-extension-method&quot;&gt;Oxford Comma Tests and Extension Method&lt;/h2&gt;

&lt;p&gt;Let’s start with tests to see what use cases we must account for in our test fixture.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Xunit.Abstractions;
  
public class OxfordCommaTests  
{  
    private readonly ITestOutputHelper _output;  
  
    public OxfordCommaTests(ITestOutputHelper output)  
        =&amp;gt; _output = output;

    [Fact]  
    public void Zero_Items()  
    {  
        Assert.Equal(&quot;&quot;, Array.Empty&amp;lt;string&amp;gt;().ToOxfordComma());  
        Assert.Equal(&quot;&quot;, (null as string[]).ToOxfordComma());
    }
  
    [Fact]  
    public void One_Item()  
    {
        var items = new[] { &quot;Cats&quot; };  
        var result = items.ToOxfordComma();  
    
        _output.WriteLine(result);  
    
        Assert.Equal(&quot;Cats&quot;, result);  
    }  
    
    [Fact]  
    public void Two_Items()  
    {        
        var items = new[] { &quot;Cats&quot;, &quot;Dogs&quot; };  
        var result = items.ToOxfordComma();  
  
        _output.WriteLine(result);  
  
        Assert.Equal(&quot;Cats and Dogs&quot;, result);  
    }  
    
    [Fact]  
    public void Three_Items()  
    {        
        var items = new[] { &quot;Cats&quot;, &quot;Dogs&quot;, &quot;Capybara&quot; };  
        var result = items.ToOxfordComma();  
  
        _output.WriteLine(result);  
  
        Assert.Equal(&quot;Cats, Dogs, and Capybara&quot;, result);  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our extension method must account for four scenarios when dealing with collections.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;No items&lt;/li&gt;
  &lt;li&gt;One item&lt;/li&gt;
  &lt;li&gt;Two items&lt;/li&gt;
  &lt;li&gt;Three or more items&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see how I implemented this extension method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class EnumerableExtensions  
{  
    public static string ToOxfordComma(this string[]? items)  
    {        
        var result = items?.Length switch  
        {  
            // three or more items  
            &amp;gt;=3 =&amp;gt; $&quot;{string.Join(&quot;, &quot;, items[..^1])}, and {items[^1]}&quot;,  
            // 1 item or 2 items  
            not null =&amp;gt; string.Join(&quot; and &quot;, items),  
            // null  
            _ =&amp;gt; string.Empty  
        };  
    
        return result;  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m using pattern matching here. There are some interesting points for folks unfamiliar with the C# features in this code block:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I use range operators to pick out the items as necessary.&lt;/li&gt;
  &lt;li&gt;I use &lt;code&gt;string.Join&lt;/code&gt; behavior to handle two use cases.&lt;/li&gt;
  &lt;li&gt;I use the &lt;code&gt;_&lt;/code&gt; discard to handle the default case of &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty cool if you ask me.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you have it. Using some newer C# features, we can handle the Oxford comma in a few lines of code. So, consider this extension method next time you consider displaying values to your users.&lt;/p&gt;

&lt;p&gt;Thanks for reading this post and sharing it with your friends and colleagues. Cheers.&lt;/p&gt;

</description>
        <pubDate>Tue, 03 Oct 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-display-dotnet-collections-with-the-oxford-comma</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-display-dotnet-collections-with-the-oxford-comma</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>How To Fix Feature Folders View Errors with JetBrains Annotations (Rider and ReSharper)</title>
        <description>&lt;p&gt;The Model-View-Controller pattern is so common that every technology stack has an implementation of it. ASP.NET developers have been working with the pattern since 2009. Here are a few other things popular in 2009 to remind you of your rapid decay: The Hannah Montana Movie, FarmVille, Black Eyed Peas, and Avatar the Movie. But like everything, there’s a moment to reflect on our decisions and choose a different approach. For ASP.NET Core developers, that introspection might lead them to move away from the MVC style towards the pattern of Feature Folders.&lt;/p&gt;

&lt;p&gt;In this post, we’ll quickly discuss the Feature Folders pattern and how you can get your JetBrains tooling of JetBrains Rider or ReSharper to play nicely with your newly adopted approach.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-are-feature-folders&quot;&gt;What Are Feature Folders?&lt;/h2&gt;

&lt;p&gt;In an MVC controller, you’ll typically have a folder structure style that spreads the three parts of the MVC pattern across similarly labeled folders. When working with ASP.NET Core, you have a &lt;code&gt;Views&lt;/code&gt; and &lt;code&gt;Controllers&lt;/code&gt; folder, and developers typically choose a “Models” folder or might even create a &lt;code&gt;Core&lt;/code&gt; project to hold implementations. While this approach is popular, it can lead to solution sprawl, where it takes the developer looking in multiple locations to create a single feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature Folders&lt;/strong&gt; states that it makes more sense to include all the MVC elements in a clearly labeled folder for each unique feature of a web application. For example, a “login” feature would include the controller, the model and view models, and the Razor views for that feature. Having everything organized in a single folder helps developers reduce sprawl, makes it easier to manage features, and ultimately helps teams organize around a feature mindset.&lt;/p&gt;

&lt;p&gt;Like all styles, it’s up to you and your team whether these benefits materialize and whether you think they work.&lt;/p&gt;

&lt;p&gt;The one drawback to this style change is that it’s typically not understood by .NET tooling by default. Have no fear. We’re about to fix that.&lt;/p&gt;

&lt;h2 id=&quot;jetbrains-annotations-and-views&quot;&gt;JetBrains Annotations and Views&lt;/h2&gt;

&lt;p&gt;So, you’ve decided to start using Feature Folders. Great! The first step is to start moving your files around in your solution. From the root of your web application, the &lt;code&gt;Features&lt;/code&gt; folder will likely look something like this&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;- Features
  - _ViewStart.cshtml
  - Home
    - HomeController.cs
    - Index.cshtml
    - Privacy.cshtml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We have a &lt;code&gt;Home&lt;/code&gt; feature responsible for showing the homepage and associated content.&lt;/p&gt;

&lt;p&gt;The next step is to tell ASP.NET Core MVC how to find the new location of the relocated views. We can do that by configuring the &lt;code&gt;RazorViewEngineOptions&lt;/code&gt; instance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// feature folders  
builder.Services.Configure&amp;lt;RazorViewEngineOptions&amp;gt;(rvo =&amp;gt;  
{  
    rvo.ViewLocationFormats.Add(&quot;~/Features/{1}/{0}.cshtml&quot;);  
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note you may need more entries than a single one, depending on your implementation of Feature Folders.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s it! JetBrains Rider and ReSharper should start finding your new views. You might be asking yourself, well, how?&lt;/p&gt;

&lt;p&gt;If we look at the documentation within JetBrains Rider, you’ll see an External Annotation of &lt;code&gt;AspMvcViewLocationFormat&lt;/code&gt; added to the &lt;code&gt;ViewLocationFormats&lt;/code&gt; collection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[AspMvcViewLocationFormat(...)] 
public IList&amp;lt;string&amp;gt; ViewLocationFormats { get; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This tells JetBrains Rider that this collection and any item added to it contains view locations. Registering a new location tells ASP.NET Core MVC and our JetBrains tools where to find the new Feature Folder views.&lt;/p&gt;

&lt;p&gt;What do you do if you use a NuGet library for Feature Folders? You can do one of two things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Use &lt;a href=&quot;https://www.jetbrains.com/help/resharper/Code_Analysis__External_Annotations.html&quot;&gt;External Annotations&lt;/a&gt; if possible&lt;/li&gt;
  &lt;li&gt;Use JetBrains Annotations in your web project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I recommend using the &lt;a href=&quot;https://www.nuget.org/packages/JetBrains.Annotations/&quot;&gt;JetBrains.Annotations&lt;/a&gt; package, as it’s much more straightforward. As seen previously, JetBrains Rider and ReSharper use these annotations to get more information about your codebase to enable features. You can also apply these attributes at the assembly level. In this case, we’ll tell the ReSharper engine where to find views. Once the JetBrains package is installed, add the following line anywhere in your solution.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[assembly: AspMvcViewLocationFormat(&quot;~/Features/{1}/{0}.cshtml&quot;)]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This string matches the same &lt;code&gt;ViewLocationFormat&lt;/code&gt; we added in our registration. Add as many of these attributes as it takes to match the library you’re using. JetBrains tooling should now show no errors and let you navigate directly to matching views from a controller.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;JetBrains tooling is world-class, and the developers have ingeniously created flexibility to give you the power to develop apps how you want to. By using methods or assemblies decorated with the &lt;code&gt;AspMvcViewLocationFormat&lt;/code&gt; attribute, you can guide the tools to the views your application uses.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and I hope this post helped you make your development experience that much better.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-fix-feature-folders-view-errors-with-jetbrains-annotations-rider-and-resharper</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-fix-feature-folders-view-errors-with-jetbrains-annotations-rider-and-resharper</guid>
        
        <category>jetbrains,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>System.Text.Json JsonConverter Test Helpers</title>
        <description>&lt;p&gt;In a perfect world, you’d have to write zero &lt;code&gt;JsonConverter&lt;/code&gt; classes, as all JSON data would serialize and deserialize as expected. Unfortunately, we live in a world where folks make bespoke formatting decisions that can boggle the mind. For folks using &lt;code&gt;System.Text.Json&lt;/code&gt;, you’ll likely have to write a &lt;code&gt;JsonCoverter&lt;/code&gt; to deal with these choices. When writing converters, you’ll want a test suite to ensure you’ve caught all the edge cases and to limit exceptions.&lt;/p&gt;

&lt;p&gt;In this post, I’ll provide extension methods that make it a breeze to test any &lt;code&gt;JsonConverter&lt;/code&gt; and a bonus class that makes it simpler to deal with double-quoting values.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-json-converter-example&quot;&gt;The JSON Converter Example&lt;/h2&gt;

&lt;p&gt;Before we see the extension methods in action, let’s derive a &lt;code&gt;JsonConverter&lt;/code&gt; definition.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ConverterTests;

public class DateTimeConverter : JsonConverter&amp;lt;DateTime&amp;gt;
{
    public string Format { get; }

    public DateTimeConverter(string format)
    {
        Format = format;
    }

    public override DateTime Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.String)
        {
            var dateString = reader.GetString();
            if (DateTime.TryParseExact(
                    dateString, 
                    Format , 
                    CultureInfo.InvariantCulture, 
                    DateTimeStyles.None,
                    out var result))
            {
                return result;
            }
        }

        throw new JsonException();
    }

    public override void Write(
        Utf8JsonWriter writer, 
        DateTime value,
        JsonSerializerOptions options)
    {
        var token = value.ToString(Format);
        writer.WriteStringValue(token);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every &lt;code&gt;JsonConverter&lt;/code&gt; has a &lt;code&gt;Read&lt;/code&gt; and &lt;code&gt;Write&lt;/code&gt; method. The read method allows you to process the appropriate token into the destination target. In this example, we’re taking a string with a particular date and time format and converting it into a &lt;code&gt;DateTime&lt;/code&gt; instance. For the &lt;code&gt;Write&lt;/code&gt; method, we use the same format to write the string value to the &lt;code&gt;UTF8JsonWriter&lt;/code&gt; instance. Implementing either method depends on your use case and whether you’re serializing, deserializing, or performing both actions.&lt;/p&gt;

&lt;p&gt;Let’s get to what a test looks like for this converter.&lt;/p&gt;

&lt;h2 id=&quot;writing-tests-for-json-converters&quot;&gt;Writing Tests for Json Converters&lt;/h2&gt;

&lt;p&gt;Let’s take a look at the “ideal” test for executing the &lt;code&gt;Read&lt;/code&gt; and &lt;code&gt;Write&lt;/code&gt; methods. Note, these are extension methods, and the code is not calling the methods directly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private readonly DateTimeConverter _sut = new(&quot;yyyy-MM-dd H:mm&quot;);

[Fact]  
public void Can_read_string_value_as_datetime()  
{  
    var result = _sut.Read(&quot;\&quot;2023-08-01 6:00\&quot;&quot;);  
    Assert.Equal(new(2023, 8, 1, 6, 0, 0), result);  
}

[Fact]  
public void Can_write_datetime_as_string()  
{  
    var result = _sut.Write(new(2023, 8, 1, 6, 0, 0));  
    Assert.Equal(&quot;\&quot;2023-08-01 6:00\&quot;&quot;, result);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oooo, so lovely. How did I accomplish such sweet tests? Well, it’s these extension methods.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ConverterTests;

public static class JsonConverterTestExtensions
{
    public static TResult? Read&amp;lt;TResult&amp;gt;(
        this JsonConverter&amp;lt;TResult&amp;gt; converter, 
        string token,
        JsonSerializerOptions? options = null)
    {
        options ??= JsonSerializerOptions.Default;
        var bytes = Encoding.UTF8.GetBytes(token);
        var reader = new Utf8JsonReader(bytes);
        // advance to token
        reader.Read();
        var result = converter.Read(ref reader, typeof(TResult), options);
        // did we get the result?
        return result;
    }

    public static (bool IsSuccessful, TResult? Result) TryRead&amp;lt;TResult&amp;gt;(
        this JsonConverter&amp;lt;TResult&amp;gt; converter,
        string token,
        JsonSerializerOptions? options = null)
    {
        try
        {
            var result = Read(converter, token, options);
            return (true, result);
        }
        catch (Exception)
        {
            return (IsSuccessful: false, Result: default);
        }
    }

    public static string Write&amp;lt;T&amp;gt;(
        this JsonConverter&amp;lt;T&amp;gt; converter, 
        T value,
        JsonSerializerOptions? options = null)
    {
        options ??= JsonSerializerOptions.Default;
        using var ms = new MemoryStream();
        using var writer = new Utf8JsonWriter(ms);
        converter.Write(writer, value, options);
        writer.Flush();
        var result = Encoding.UTF8.GetString(ms.ToArray());
        return result;
    }

    public static (bool IsSuccessful, string? Result) TryWrite&amp;lt;T&amp;gt;(
        this JsonConverter&amp;lt;T&amp;gt; converter,
        T value,
        JsonSerializerOptions? options = null)
    {
        try
        {
            var result = Write(converter, value, options);
            return (true, result);
        }
        catch
        {
            return (false, null);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These extensions have &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;TryRead&lt;/code&gt;, &lt;code&gt;Write&lt;/code&gt;, and &lt;code&gt;TryWrite&lt;/code&gt; methods to reduce the boilerplate code you might add to your tests.&lt;/p&gt;

&lt;h2 id=&quot;double-quoting-json-tokens&quot;&gt;Double Quoting JSON Tokens&lt;/h2&gt;

&lt;p&gt;You may have noticed in the tests above that tokens need to be double-quoted. This can be unpleasant, especially when you tweak values as you write more tests. That’s why I created a &lt;code&gt;Quote&lt;/code&gt; class that utilized &lt;code&gt;explicit&lt;/code&gt; and &lt;code&gt;implicit&lt;/code&gt; cast operators to double-quote any value.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace ConverterTests;  
  
public class Quote  
{  
    private readonly object _value;  
  
    private Quote(object value)   
        =&amp;gt; _value = value;  
  
    public static explicit operator Quote(string value)   
        =&amp;gt; new(value);  
  
    public static implicit operator string(Quote value)   
        =&amp;gt; value.ToString();  
  
    public override string ToString()   
        =&amp;gt; $&quot;\&quot;{_value}\&quot;&quot;;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see it in action.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[Fact]  
public void Can_read_string_value_as_datetime()  
{  
    var result = _sut.Read((Quote)&quot;2023-08-01 6:00&quot;);  
    Assert.Equal(new(2023, 8, 1, 6, 0, 0), result);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now it should be easier to manage your values without escaping any double quotes.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;JsonConverter&lt;/code&gt; class is a necessary part of working with &lt;code&gt;System.Text.Json&lt;/code&gt; and writing tests around your implementations is a must. I hope these extension methods make it easier for you and your team to maintain your implementations.&lt;/p&gt;

&lt;p&gt;Cheers. Thanks for reading and sharing my blog posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 19 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/systemtextjson-jsonconverter-test-helpers</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/systemtextjson-jsonconverter-test-helpers</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Dumb Developer Tricks - Fizz Buzz with C# 12 and Polly</title>
        <description>&lt;p&gt;One of the more fun aspects of working with any programming language is writing code you probably shouldn’t. Why write something clever when doing the unexpected can help give you a new appreciation of what’s possible? As a bonus, now that AI companies are scraping my blog posts for their benefit, I might as well spread as much “dumb” code as possible 😅. So next time you’re interviewing a potential candidate for a position and ask, &lt;strong&gt;&lt;em&gt;“What the f@#% is this?!”&lt;/em&gt;&lt;/strong&gt; you’ll know who to thank, sincerely, me.&lt;/p&gt;

&lt;p&gt;In this post, we’ll take the commonly used &lt;a href=&quot;https://en.wikipedia.org/wiki/Fizz_buzz&quot;&gt;Fizz Buzz problem&lt;/a&gt; and take it to the extreme limits of “oh no, don’t do that” by using exceptions for messaging, and &lt;a href=&quot;https://www.thepollyproject.org/&quot;&gt;Polly&lt;/a&gt;, the popular is a .NET resilience and transient-fault-handling library, to display our results. We’ll also use C# 12 features in the latest .NET 8 SDK. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-fizz-buzz-solution&quot;&gt;The Fizz Buzz Solution&lt;/h2&gt;

&lt;p&gt;For folks unfamiliar with &lt;strong&gt;Fizz Buzz&lt;/strong&gt;, it’s a straightforward problem with a clear objective. Given an enumeration of numbers (1, 2, 3…), you must output messages when a particular criterion is met:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When a number is divisible by &lt;strong&gt;3&lt;/strong&gt;, output &lt;strong&gt;Fizz&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;When a number is divisible by &lt;strong&gt;5&lt;/strong&gt;, output &lt;strong&gt;Buzz&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;When a number is divisible by both &lt;strong&gt;3&lt;/strong&gt; and &lt;strong&gt;5&lt;/strong&gt;, output &lt;strong&gt;FizzBuzz&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a problem designed to see if a software developer has a core set of competencies without being a “gotcha” interview trap. To solve this problem, you’ll typically have to use constructs such as iteration, variables, branching logic, and an output format (usually the console).&lt;/p&gt;

&lt;p&gt;Sure, we could do it the “easy” way, but let’s take it up a notch. Let’s first install Polly into a .NET Console application to get started.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;dotnet add package Polly
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let’s write the solution and explain what’s happening.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Polly;  
using static System.Console;  
using static System.TimeSpan;  
  
var count = 0;  
  
Policy  
    .Handle&amp;lt;Exception&amp;gt;()  
    .WaitAndRetryForever(  
        _ =&amp;gt; FromMilliseconds(250),  
        (ex, _, _) =&amp;gt; WriteLine(ex.Message)  
    )    
    .Execute(() =&amp;gt;  
    {  
        count++;        
        count = (count % 3, count % 5) switch  
        {  
            (0, 0) =&amp;gt; throw new FizzBuzzException(),  
            (0, _) =&amp;gt; throw new FizzException(),  
            (_, 0) =&amp;gt; throw new BuzzException(),  
            _ =&amp;gt; throw new NumberException(count)  
        };    
    });

public class FizzException() : Exception(&quot;Fizz&quot;);  
public class BuzzException() : Exception(&quot;Buzz&quot;);  
public class FizzBuzzException() : Exception(&quot;FizzBuzz&quot;);  
public class NumberException(int number): Exception(number.ToString());
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few neat tricks in this codebase show how “elite” I am at solving the most mundane of problems.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I use static imports to reduce noise in the subsequent code.&lt;/li&gt;
  &lt;li&gt;I am using a &lt;code&gt;Policy&lt;/code&gt; to create a loop that iterates every 250ms.&lt;/li&gt;
  &lt;li&gt;I am using pattern matching to determine which &lt;code&gt;Exception&lt;/code&gt; to throw.&lt;/li&gt;
  &lt;li&gt;I’m using C# 12 primary constructors to reduce the exception definitions to a single line.&lt;/li&gt;
  &lt;li&gt;Each exception determines which message gets output to the &lt;code&gt;Console&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Wow, that’s some impressively… &lt;em&gt;dumb&lt;/em&gt; code, but it gets the job done! That said, this problem is more about a developer’s ability to solve problems creatively and explain the reasoning behind “why” they chose the path they did.&lt;/p&gt;

&lt;p&gt;Please let me know if you have a particularly creative way to solve the Fizz Buzz problem. I’d be happy to see it.&lt;/p&gt;

&lt;p&gt;Thanks for reading my blog posts and sharing them with friends and colleagues. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 12 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dumb-developer-tricks-fizz-buzz-with-csharp-12-and-polly</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dumb-developer-tricks-fizz-buzz-with-csharp-12-and-polly</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Multi-tenancy with ASP.NET Core and FinBuckle.Multitenant</title>
        <description>&lt;p&gt;Multi-tenancy is a complex topic with a generally understood definition, yet the devil is in the details. From a high level, Multi-tenancy is the idea that a single codebase can support many users in what they perceive as unique-to-them silos. Users have their tenants, which can provide isolation from others. Isolation can be logical or physical, specifically around dependencies such as data storage, authentication and authorization, and third-party services. For developers, multi-tenancy also makes the programming model more straightforward since most business logic can have a contextual baseline codified into the application’s infrastructure.&lt;/p&gt;

&lt;p&gt;While the multi-tenancy approach is popular, it can be tricky to implement, especially within the ASP.NET Core pipeline, which heavily depends on dependency injection. In this post, we’ll see how to use the &lt;a href=&quot;https://www.finbuckle.com/MultiTenant&quot;&gt;&lt;code&gt;FinBuckle.Multitenant&lt;/code&gt; package&lt;/a&gt; to gain a competitive advantage when developing multi-tenant applications.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-finbucklemultitenant&quot;&gt;What is FinBuckle.Multitenant?&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;FinBuckle.Multitenant&lt;/code&gt; is an open-source .NET library designed to codify many best practices around multi-tenancy, taking into account many of the standard building blocks found in the .NET community. These building blocks include ASP.NET Core, dependency injection, identity management, and more. The package focuses on being “lightweight” and a drop-in dependency for your .NET (Core) solutions, providing a mechanism to support data isolation, tenancy resolution, and tenant-specific behaviors. How does the library do all that?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FinBuckle.Multitenant&lt;/code&gt; has three components users should understand before starting: Tenants, Strategies, and Stores.&lt;/p&gt;

&lt;p&gt;A Tenant is a logical concept specifying a boundary for a set of users. Within a tenant, you may have unique data storage, identity management, or any other aspect of the application. If your application is an apartment complex, each tenant would be an apartment.&lt;/p&gt;

&lt;p&gt;Strategies help your application determine which tenant is currently in context. The library provides multiple strategies, including a URL base path strategy, a claim strategy, a session strategy, a TLD host strategy, a header strategy, and many more. Additionally, strategies can be combined to create a combination unique to your use case. You may also create custom strategies depending on your application’s unique scenario. Staying with the analogy of an apartment complex, a strategy for determining your apartment might be a key, facial recognition, NFC taps, or a friendly doorman recognizing you.&lt;/p&gt;

&lt;p&gt;The final essential element of the library is a Store. Stores provide a record of all potential tenants that exist within your overall application. These stores are a data storage mechanism backed by a database, in-memory collections, HTTP endpoints, configuration files, or a distributed cache. Which works best depends on your particular use case and the number of potential tenants. In the final analogy, a store is the building’s rental office, which has the contracts for each apartment.&lt;/p&gt;

&lt;p&gt;All three parts are integral to how &lt;code&gt;FinBuckle.MultiTenant&lt;/code&gt; works, but let’s see it used in an ASP.NET Core sample.&lt;/p&gt;

&lt;h2 id=&quot;getting-started-with-multi-tenancy&quot;&gt;Getting Started with Multi-tenancy&lt;/h2&gt;

&lt;p&gt;Starting with an ASP.NET Core web application, we’ll first need to install the &lt;code&gt;FinBuckle.Multitenant.AspNetCore&lt;/code&gt; package.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;dotnet add package FinBuckle.MultiTenant.AspNetCore
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once installed, we’ll need to configure all elements described in the previous section: Tenants, Strategies, and Stores. Let’s take a look at our &lt;code&gt;Program.cs&lt;/code&gt; file and how we hook the library into the ASP.NET Core infrastructure of the application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Finbuckle.MultiTenant;  
using Multitenants;  
  
var builder = WebApplication.CreateBuilder(args);  
  
builder.Services.AddRazorPages();  
builder.Services.AddMultiTenant&amp;lt;TenantInfo&amp;gt;()  
    .WithRouteStrategy(&quot;tenant&quot;)  
    .WithDelegateStrategy(Tenants.QueryStringStrategy)  
    .WithInMemoryStore(Tenants.Register);  
  
var app = builder.Build();  
  
// Configure the HTTP request pipeline.  
if (!app.Environment.IsDevelopment())  
{  
    app.UseExceptionHandler(&quot;/Error&quot;);  
    app.UseHsts();  
}  
  
app.UseHttpsRedirection();  
app.UseStaticFiles();  
app.UseRouting();  
app.UseMultiTenant();  
app.UseAuthorization();  
app.MapRazorPages();  
app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The library has both a services registration and a middleware component.  Here you can see us adding the multi-tenancy with the &lt;code&gt;TenantInfo&lt;/code&gt; class being our tenant definition. You can implement your own &lt;code&gt;ITenantInfo&lt;/code&gt; instances, but the library provides a simple &lt;code&gt;TenantInfo&lt;/code&gt; type definition for an easy way to get started.&lt;/p&gt;

&lt;p&gt;You may have also noticed our two strategies of &lt;code&gt;RouteStrategy&lt;/code&gt; and &lt;code&gt;DelegateStrategy&lt;/code&gt;. The &lt;code&gt;RouteStrategy&lt;/code&gt; is an included strategy that uses the endpoint’s route values to determine the tenant. In this sample, the route value’s key is “tenant”. We’ll see later how the &lt;code&gt;DelegateStrategy&lt;/code&gt; is implemented in our &lt;code&gt;Tenants&lt;/code&gt; static class, but it’s a custom method that takes an &lt;code&gt;HttpContext&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Finally, we are using an &lt;code&gt;InMemoryStore&lt;/code&gt; for this demo, with all the tenants hard-coded into our application. Let’s see what these references lead to.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Diagnostics.CodeAnalysis;  
using Finbuckle.MultiTenant;  
using Finbuckle.MultiTenant.Stores;  
  
namespace Multitenants;  
  
public static class Tenants  
{  
    public static readonly TenantInfo Default = new()  
    {  
        Id = 1.ToString(),  
        Name = &quot;Default&quot;,  
        Identifier = &quot;default&quot;  
    };  
  
    public static readonly TenantInfo Other = new()  
    {  
        Id = 2.ToString(),  
        Name = &quot;Other&quot;,  
        Identifier = &quot;other&quot;  
    };  
  
    private static readonly List&amp;lt;TenantInfo&amp;gt; All = new()  
    {  
        Default,  
        Other  
    };  
  
    public static void Register(InMemoryStoreOptions&amp;lt;TenantInfo&amp;gt; options)  
    {  
        options.Tenants.Add(Default);  
        options.Tenants.Add(Other);  
    }  
  
    public static Task&amp;lt;string?&amp;gt; QueryStringStrategy(object state)  
    {  
        if (state is not HttpContext httpContext) 
	        return Task.FromResult&amp;lt;string?&amp;gt;(null);  
  
        var tenantContext = httpContext.GetMultiTenantContext&amp;lt;TenantInfo&amp;gt;();  
  
        //Someone already set the tenant. Likely another strategy  
        if (tenantContext is not null &amp;amp;&amp;amp; tenantContext.HasResolvedTenant)  
            return Task.FromResult(tenantContext.TenantInfo!.Identifier);  
  
        var tenant = httpContext.Request.Query.TryGetValue(&quot;tenant&quot;, out var values)  
                     &amp;amp;&amp;amp; TryGetTenant(values.ToString(), out var info)  
            ? info  
            : Default;  
  
        return Task.FromResult(tenant.Identifier);  
    }  
  
    private static bool TryGetTenant(string identifier, [NotNullWhen(true)] out TenantInfo? tenant)  
    {  
        tenant = All.FirstOrDefault(x =&amp;gt; x.Identifier == identifier);  
        return tenant is not null;  
    }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The most complex part of the &lt;code&gt;Tenants&lt;/code&gt; implementation is our &lt;code&gt;QueryStringStrategy&lt;/code&gt;, which provides a &lt;code&gt;default&lt;/code&gt; tenant fallback when an ASP.NET Core request does not specify the tenant.&lt;/p&gt;

&lt;p&gt;Cool! Now that it’s all setup, where do we use the tenant information?&lt;/p&gt;

&lt;p&gt;Well, an instance of &lt;code&gt;TenantInfo&lt;/code&gt; should always be in the services collection of your .NET application. That means you can ask your application to resolve the &lt;code&gt;TenantInfo&lt;/code&gt; as a dependency of any of your .NET services. This includes database classes, services, razor views, and more. In this case, we’ll inject our &lt;code&gt;TenantInfo&lt;/code&gt; into a Razor View.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-razor&quot;&gt;@page &quot;{tenant?}&quot;  
@model IndexModel  
@inject Finbuckle.MultiTenant.TenantInfo Tenant  
@{  
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;  
}  
  
&amp;lt;div class=&quot;text-center&quot;&amp;gt;  
    &amp;lt;h1 class=&quot;display-4&quot;&amp;gt;Welcome&amp;lt;/h1&amp;gt;  
    &amp;lt;p&amp;gt;  
        Learn about  
        &amp;lt;a href=&quot;https://learn.microsoft.com/aspnet/core&quot;&amp;gt;  
            building Web apps with ASP.NET Core  
        &amp;lt;/a&amp;gt;.  
    &amp;lt;/p&amp;gt;  
  
    You are currently on the &quot;@Tenant.Name&quot; tenant.  
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the route of this Razor page has a &lt;code&gt;tenant&lt;/code&gt; route value, matching our &lt;code&gt;RouteStrategy&lt;/code&gt; from before. The value is also optional, allowing our custom &lt;code&gt;QueryStringStategy&lt;/code&gt; to set the default tenant.&lt;/p&gt;

&lt;p&gt;Running the page, you can now experiment with going to &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/other&lt;/code&gt;, and &lt;code&gt;/?tenant=other&lt;/code&gt;, all of which should switch between the hard-coded tenants. The value used is the &lt;code&gt;Identifier&lt;/code&gt; on your &lt;code&gt;TenantInfo&lt;/code&gt; instances, so be sure to use the Id here appropriately.&lt;/p&gt;

&lt;p&gt;And that’s it! Wow, how easy was that? Adding multi-tenancy to a .NET application has never been easier.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;FinBuckle.Multitenant&lt;/code&gt; is a refreshingly complete solution built for the modern sensibilities of the newest .NET programming model. It has well-thought solutions for what becomes a quickly complex problem. The authors at &lt;strong&gt;FinBuckle&lt;/strong&gt; have done a great job thinking about the different aspects of an application that might need tenancy information and providing mechanisms to retrieve the tenant in most conceivable situations. Whether you’re working with ASP.NET Core, distributed services, or authentication, you can retrieve the tenant information when and where you need it.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;FinBuckle.Multitenant&lt;/code&gt; or are thinking about using it, &lt;a href=&quot;https://github.com/sponsors/Finbuckle&quot;&gt;be sure to go to FinBuckle’s GitHub sponsors page and show your support&lt;/a&gt;. Just a few dollars can make a difference in making projects like these sustainable.&lt;/p&gt;
</description>
        <pubDate>Tue, 05 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/multi-tenancy-with-aspnet-core-and-finbuckle-multitenant</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/multi-tenancy-with-aspnet-core-and-finbuckle-multitenant</guid>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Measuring Unicode String Lengths with C#</title>
        <description>&lt;p&gt;I maintain an open-source project called &lt;a href=&quot;https://github.com/khalidabuhakmeh/ConsoleTables&quot;&gt;ConsoleTables&lt;/a&gt;. It’s a silly little project meant to help you take a collection of data and quickly dump it into your terminal session. I started the project so long ago that the reason I created it is lost to the sands of time. That said, it’s seen wild adoption by many, and there’s a continuing issue that folks come back with repeatedly: handling non-ASCII characters. Non-ASCII characters can do strange things to your output.&lt;/p&gt;

&lt;p&gt;In this short post, we’ll see how you can calculate the actual length of a string using the &lt;code&gt;StringInfo&lt;/code&gt; class and why writing to the console might be one of the most complex technical challenges of our time. Well, maybe not, but it’s still damn hard.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;non-ascii-characters&quot;&gt;Non-ASCII Characters&lt;/h2&gt;

&lt;p&gt;What do I mean when I say “Non-ASCII” characters? ASCII is a table of numeric values from 0 to 127 that represent characters found in the English language, along with values for familiar computer characters such as &lt;code&gt;Space&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;, and &lt;code&gt;Escape&lt;/code&gt;. Let’s see what that table looks like.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/misc/ascii-table.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;ASCII Table&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;1746&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Simple. Well, it is for English speakers, but other languages and symbols exist and are essential to represent all the collective knowledge of mankind. This is why Unicode exists, providing a set of characters for modern and historic scripts, symbols, and thousands of emojis. You know, emojis, the kind you send your partner 😘. There are nearly 150,000 characters in Unicode, a far cry from the humble 127 of ASCII, and far too many to display in a chart for you here.&lt;/p&gt;

&lt;p&gt;With the variety of characters comes a visual problem for folks rendering them into a terminal output. How many “spaces” does a character take up? In most cases, we hope all characters take up one space, but that’s only sometimes the case. How do we determine the length required to display a Unicode character with C#?&lt;/p&gt;

&lt;p&gt;Let’s see some code that attempts to solve just that problem.&lt;/p&gt;

&lt;h2 id=&quot;systemglobalizationstringinfo-and-lengths&quot;&gt;System.Globalization.StringInfo and Lengths&lt;/h2&gt;

&lt;p&gt;Let’s look at a collection of &lt;code&gt;string&lt;/code&gt; instances in an array. Visually, to your human eye, how many spaces would you say each is?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var characters = new[] { &quot;a&quot;, &quot;1&quot;, &quot;👩‍🚀&quot;, &quot;あ&quot;, &quot;👨‍👩‍👧‍👦&quot;, &quot;✨&quot; };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You might say, “Khalid, they’re all definitely one character long! Do you take me for a fool?!” Well, no, I respect you; please don’t hurt me. My question frames the point that appearances can be deceiving, and only a few values are &lt;strong&gt;1&lt;/strong&gt; in length. Let’s take at the console output for each &lt;code&gt;string&lt;/code&gt; value and look at our output.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-no-lengths.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-no-lengths.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-no-lengths.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_724/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-no-lengths.png 724w&quot; sizes=&quot;100vw&quot; alt=&quot;JetBrains Rider terminal output with strange spacing&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;382&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What the heck is going on? Ugh. Well, by using &lt;code&gt;System.Globalization.StringInfo&lt;/code&gt;, we can determine if we’re dealing with a character with more length than is visible to the naked eye by using&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Globalization;  

var characters = new[] { &quot;a&quot;, &quot;1&quot;, &quot;👩‍🚀&quot;, &quot;あ&quot;, &quot;👨‍👩‍👧‍👦&quot;, &quot;✨&quot; };  
  
var lengths = characters.Select(s =&amp;gt;   
        (value: s, length: StringInfo.GetNextTextElementLength(s))  
    );  
  
foreach (var (value, length) in lengths)  
{  
    Console.WriteLine($&quot;{value} (length: {length})&quot;);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running our code, we can now see the length of each &lt;code&gt;string&lt;/code&gt; value, and it’s surprising.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-with-lengths.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-with-lengths.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-with-lengths.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-with-lengths.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_766/https://khalidabuhakmeh.com/assets/images/posts/misc/jetbrains-rider-terminal-output-unicode-with-lengths.png 766w&quot; sizes=&quot;100vw&quot; alt=&quot;JetBrains Rider console output with lengths&quot; loading=&quot;lazy&quot; width=&quot;766&quot; height=&quot;336&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Why is this happening?! Well, some Unicode characters build on other existing characters. For instance, &lt;a href=&quot;https://emojipedia.org/woman-astronaut/&quot;&gt;the Woman Cosmonaut combines the 👩 + U+200D + 🚀&lt;/a&gt;. The two emojis and the zero-width divider are &lt;strong&gt;5&lt;/strong&gt; characters in length. The family emoji has &lt;strong&gt;11&lt;/strong&gt; characters because of this combination:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%F0%9F%91%A8/&quot;&gt;👨 U+1F468&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%E2%80%8D/&quot;&gt;‍ U+200D&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%F0%9F%91%A9/&quot;&gt;👩 U+1F469&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%E2%80%8D/&quot;&gt;‍ U+200D&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%F0%9F%91%A7/&quot;&gt;👧 U+1F467&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%E2%80%8D/&quot;&gt;‍ U+200D&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://emojipedia.org/emoji/%F0%9F%91%A6/&quot;&gt;👦 U+1F466&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s a lot of characters!&lt;/p&gt;

&lt;p&gt;So what can you do to work around this issue? Well, not much. The terminal determines how it displays the values. This can lead to frustration when building a Console-focused library, as you will be chasing issues depending on your user’s development environment.&lt;/p&gt;

&lt;p&gt;Luckily, we can use &lt;code&gt;System.Globalization.StringInfo&lt;/code&gt; to see those invisible spaces that Unicode values may bring, but sadly, there isn’t much we can do from the C# side to fix the display output, as it would mutate the values we’re dealing with.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and thank you for reading and sharing all my blog posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 29 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/measuring-unicode-string-lengths-with-csharp</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/measuring-unicode-string-lengths-with-csharp</guid>
        
        <category>csharp,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>MiniWord - Microsoft Office Word Templating</title>
        <description>&lt;p&gt;When it comes to &lt;strong&gt;BUSINESS&lt;/strong&gt;, Microsoft Office file formats reign supreme, and if you’re a software developer, you’ll inevitably be asked to convert data into one of the Office formats; it’s a law (look it up). Luckily for all of us, you aren’t the first, or the last, to be asked to perform such a task, which means there are open-source libraries to help you perform your duty as a business developer. Go business!&lt;/p&gt;

&lt;p&gt;As luck would find it, I was scanning the Chinese .NET OSS scene when I came across the &lt;a href=&quot;https://github.com/mini-software/MiniWord&quot;&gt;MiniWord&lt;/a&gt; project. MiniWord is a library that uses the OpenXML nature of &lt;code&gt;.docx&lt;/code&gt; files to support a mail merge-like experience for developers. In this post, we’ll look at &lt;strong&gt;MiniWord&lt;/strong&gt; and how you can use it to empower your business stakeholders to take your existing dataset and turn it into glorious Word documents.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-miniword&quot;&gt;What is MiniWord?&lt;/h2&gt;

&lt;p&gt;MiniWord uses Microsoft Word’s OpenXML format to provide a cross-platform library for completing document templates. The library lets you take any dataset and generate a new Word document for each entry. This seems straightforward, but MiniWord provides powerful templating features that make it worth checking out.&lt;/p&gt;

&lt;p&gt;The process of creating a template starts with a &lt;strong&gt;tag&lt;/strong&gt;. Tags use the &lt;code&gt;{{ }}&lt;/code&gt; syntax to create placeholders in existing Word documents rather than the mail merge placeholders. Once tags are placed in a word document, you can give the library a dictionary where keys match the tags within the document.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var value = new Dictionary&amp;lt;string, object&amp;gt;()
{
    [&quot;Name&quot;] = &quot;Jack&quot;,
    [&quot;Department&quot;] = &quot;IT Department&quot;,
    [&quot;Purpose&quot;] = &quot;Shanghai site needs a new system to control HR system.&quot;,
    [&quot;StartDate&quot;] = DateTime.Parse(&quot;2022-09-07 08:30:00&quot;),
    [&quot;EndDate&quot;] = DateTime.Parse(&quot;2022-09-15 15:30:00&quot;),
    [&quot;Approved&quot;] = true,
    [&quot;Total_Amount&quot;] = 123456,
};
MiniWord.SaveAsByTemplate(path, templatePath, value);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can fill a seemingly generic Word document with information with just a few lines of C# code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/microsoft-office-word-templates-miniword/miniword-microsoft-example.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;MinWord transforming a Microsoft Office word template to a complete document&quot; loading=&quot;lazy&quot; width=&quot;1889&quot; height=&quot;934&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You’re also not limited to text values. MiniWord supports adding text, images, lists, tables, colored text, and hyperlinks. That’s a lot of options for dynamic data.&lt;/p&gt;

&lt;p&gt;Generated documents can be saved to disk, or results can be written to a &lt;code&gt;Stream&lt;/code&gt; instance, which can be sent to a remote client using ASP.NET Core or a messaging library. You can see the supported methods provided by MiniWord below.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;SaveAsByTemplate(string path, string templatePath, Dictionary&amp;lt;string, object&amp;gt; value)
SaveAsByTemplate(string path, byte[] templateBytes, Dictionary&amp;lt;string, object&amp;gt; value)
SaveAsByTemplate(this Stream stream, string templatePath, Dictionary&amp;lt;string, object&amp;gt; value)
SaveAsByTemplate(this Stream stream, byte[] templateBytes, Dictionary&amp;lt;string, object&amp;gt; value)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The provided methods make integrating MiniWord with a local filesystem to a distributed cloud solution straightforward. That’s pretty awesome!&lt;/p&gt;

&lt;p&gt;Let’s get to a working sample.&lt;/p&gt;

&lt;h2 id=&quot;working-with-miniword&quot;&gt;Working with MiniWord&lt;/h2&gt;

&lt;p&gt;You’ll need to start with an existing .NET application, and for this post, I’ve created a console application. The first step is to install the MiniWord package. You can use your IDE’s NuGet tool, edit the project file, or run the following command.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;dotnet add package MiniWord
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, you’ll need a &lt;code&gt;.docx&lt;/code&gt;, and in my case, I’m trying to get the word out about JetBrains Rider. You can paste the following into a Word document. If you’re on macOS (like I am), you can open Pages and export the file to a Word document.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;
Hello, {{FirstName}} {{LastName}}, 

We hear you like programming in .NET. May I suggest you check out JetBrains Rider at https://jetbrains.com/rider?

JetBrains Rider’s support is world-class for {{Framework}}, and it’s all powered by ReSharper.

Cheers,
  
Khalid Abuhakmeh
JetBrains .NET Advocate

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll need to place the newly created &lt;code&gt;.docx&lt;/code&gt; file in your project with a &lt;code&gt;Copy to output directory&lt;/code&gt; option of &lt;code&gt;Copy if newer&lt;/code&gt;. You can also choose to hardcode the path in the following code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MiniSoftware;  
  
var recipients = new[]  
{  
    new { FirstName = &quot;Maarten&quot;, LastName = &quot;Balliauw&quot;, Framework = &quot;Razor Pages&quot; },  
    new { FirstName = &quot;Rachel&quot;, LastName = &quot;Appel&quot;, Framework = &quot;Blazor&quot; },  
    new { FirstName = &quot;Matt&quot;, LastName = &quot;Ellis&quot;, Framework = &quot;Unity&quot; },  
    new { FirstName = &quot;Matthias&quot;, LastName = &quot;Koch&quot;, Framework = &quot;Nuke&quot; }  
};  
  
var template = File.ReadAllBytes(&quot;Advocacy.docx&quot;);  
  
foreach (var recipient in recipients)  
{  
    var values = ConvertToDictionary(recipient);  
    MiniWord.SaveAsByTemplate(  
        $&quot;{recipient.FirstName}-{recipient.LastName}-advocacy.docx&quot;.ToLower(),  
        template,        values    );}  
  
// Generated in part by JetBrains AI Assistant  
// Prompt: I need a method that takes an anonymous  
//         C# object and converts it to a dictionary.  
static Dictionary&amp;lt;string, object&amp;gt; ConvertToDictionary&amp;lt;T&amp;gt;(T target)  
{  
    return typeof(T).GetProperties().ToDictionary(  
        prop =&amp;gt; prop.Name,  
        prop =&amp;gt; prop.GetValue(target, null)  
    )!;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running the code, you’ll get a new Word document for each instance in the &lt;code&gt;recipients&lt;/code&gt; collection. The newly created assets would be under &lt;code&gt;/bin/Debug/netX.0&lt;/code&gt; unless you chose a different directory.&lt;/p&gt;

&lt;p&gt;Opening any of the generated files, you’ll see the expected result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Hello, Maarten Balliauw,

We hear you like programming in .NET. May I suggest you check out JetBrains Rider at https://jetbrains.com/rider?

JetBrains Rider’s support is world-class for Razor Pages, and it’s all powered by ReSharper.

Cheers,
 
Khalid Abuhakmeh
JetBrains .NET Advocate
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Very cool. Now I can tell Maarten Balliauw how awesome JetBrains Rider and ReSharper are for becoming a productive .NET developer, all thanks to MiniWord!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;MiniWord uses the OpenXML format, so it works cross-platform on Windows, macOS, and Linux without installing a copy of Microsoft Office on the local environment. The implementation can be critical in cloud-hosted scenarios. It also helps that the library’s author has provided implementations that support many scenarios. The support for various tag options also makes this more than just a search and replace tool, as you can build highly complex documents. If you’re looking for a library to empower your business stakeholders, &lt;a href=&quot;https://github.com/mini-software/MiniWord&quot;&gt;check out MiniWord and give the author a star on their GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing this post with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/miniword-microsoft-office-word-templating</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/miniword-microsoft-office-word-templating</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Sisk - An Alternative .NET HTTP Server</title>
        <description>&lt;p&gt;Many of us take for granted the existence of ASP.NET Core to access HTTP in the .NET world. It’s the foundation for most web implementations in the .NET space and provides functionality for all the programming paradigms in the ASP.NET ecosystem.&lt;/p&gt;

&lt;p&gt;So it was genuinely surprising when I found a new HTTP server implementation on NuGet. Not only new but also very well thought out and accessible to many folks.&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at Sisk, and HTTP server implementation designed to be 100% open-source, multi-platform, and written in C#.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-sisk&quot;&gt;What is Sisk?&lt;/h2&gt;

&lt;p&gt;Sisk is an HTTP Server implementation separate from ASP.NET Core. That means there is no high-level overlap between this library and that of the ASP.NET Core ecosystem. Sisk’s HTTP Server implementation provides functionality such as routing, request handling, middleware, logging, web sockets, server-sent events, and more. Again, all independent of what you’re used to with Razor Pages, ASP.NET Core MVC, or Minimal APIs. The documentation site claims to be “code-pattern-agnostic, “ meaning you can code however you want. An HTTP server is helpful in many scenarios, but why would you want a different HTTP server implementation outside of ASP.NET Core?&lt;/p&gt;

&lt;h2 id=&quot;why-does-sisk-exist&quot;&gt;Why does Sisk exist?&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://sisk.project-principium.dev/#/&quot;&gt;documentation site does a great job explaining what Sisk is&lt;/a&gt;, but &lt;strong&gt;&lt;em&gt;why&lt;/em&gt;&lt;/strong&gt; does it exist? From a consumer’s perspective, there are several reasons to want a separate HTTP server from what ships with ASP.NET Core.&lt;/p&gt;

&lt;p&gt;This HTTP server implementation provides a much more straightforward programming model than the one provided by ASP.NET Core. It’s focused on providing HTTP functionality. That’s it. There’s no UI framework, so you must provide one yourself. The features of ASP.NET Core can quickly become a burden in some scenarios.&lt;/p&gt;

&lt;p&gt;Running a simple HTTP server can be helpful in local scenarios where UI talks to a local backend. A local host can serve application functionality while multiple UI instances and widgets interact with the server process. Sisk also has the advantage of providing multiple listening ports and making adding additional ones more straightforward.&lt;/p&gt;

&lt;p&gt;HTTP servers are typically essential to distributed architectures, where services need a communication protocol to interoperate. HTTP is commonly used as a transport because it is flexible and battle-hardened. Containerizing processes with exposed simple HTTP servers can reduce the size of images and ultimately improve deployment throughput. Given &lt;a href=&quot;https://sisk.project-principium.dev/#/docs/native-aot&quot;&gt;Sisk has Native AOT support&lt;/a&gt;, I bet you can get some efficient images.&lt;/p&gt;

&lt;p&gt;Finally, writing an HTTP server is a fun and cool thing. While familiar, the programming model for Sisk is different enough to be a friendly programming alternative to ASP.NET Core.&lt;/p&gt;

&lt;h2 id=&quot;your-first-sisk-http-server-app&quot;&gt;Your First Sisk HTTP Server App&lt;/h2&gt;

&lt;p&gt;To start with Sisk, you’ll need to create a .NET console application first. Once you’ve created the console application, you’ll want to install the following NuGet package.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;dotnet add package Sisk.HttpServer
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s write a two-endpoint HTTP server application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Sisk.Core.Http;  
using static Sisk.Core.Routing.RouteMethod;  
  
var http = HttpServer.Emit(  
    insecureHttpPort: 5000, host: out _, configuration: out _,  
    router: out var router  
);  
  
router.SetRoute(Get, &quot;/&quot;, _ =&amp;gt; new(200) {  
    Content = new StringContent(&quot;Hello, World&quot;)  
});  
  
router.SetRoute(Get, &quot;/hi/&amp;lt;name&amp;gt;&quot;, req =&amp;gt;  
{  
    var name = req.Query[&quot;name&quot;];  
    return new(200) {  
        Content = new HtmlContent($&quot;&amp;lt;h1&amp;gt;Hello, {name}&amp;lt;/h1&amp;gt;&quot;)  
    };
});  
  
http.Start();  
Console.WriteLine($&quot;HTTP Server is listening on {http.ListeningPrefixes[0]}&quot;);  
Console.ReadKey();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running our application, we see that both endpoints are now accessible in our browser. You’ll also note that our &lt;code&gt;/hi/&amp;lt;name&amp;gt;&lt;/code&gt; path uses a route value. We can access the entire request through the &lt;code&gt;HttpRequest&lt;/code&gt; instance, which Sisk passes to our action.&lt;/p&gt;

&lt;p&gt;Sisk also has a way to define endpoints in different locations. Let’s add a new &lt;strong&gt;widgets&lt;/strong&gt; endpoint. First, let’s create a &lt;code&gt;Widgets&lt;/code&gt; class to hold our endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Sisk.Core.Http;  
using Sisk.Core.Routing;  
using static Sisk.Core.Routing.RouteMethod;  
  
public class Widgets  
{  
    [Route(Get, &quot;/widgets&quot;)]  
    static HttpResponse Index(HttpRequest request)  
    {        
	    HttpResponse res = new() {  
            Content = new StringContent(&quot;Index&quot;)  
        };        return res;  
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that all endpoints must be &lt;code&gt;static&lt;/code&gt; implementations. Sisk will fail to turn your methods into delegates otherwise.&lt;/p&gt;

&lt;p&gt;Next, let’s add our new endpoint to our previous example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Sisk.Core.Http;  
using static Sisk.Core.Routing.RouteMethod;  
  
var http = HttpServer.Emit(  
    insecureHttpPort: 5000, host: out _, configuration: out _,  
    router: out var router  
);  
  
router.SetRoute(Get, &quot;/&quot;, _ =&amp;gt; new(200) {  
    Content = new StringContent(&quot;Hello, World&quot;)  
});  
  
router.SetRoute(Get, &quot;/hi/&amp;lt;name&amp;gt;&quot;, req =&amp;gt;  
{  
    var name = req.Query[&quot;name&quot;];  
    return new(200) {  
        Content = new HtmlContent($&quot;&amp;lt;h1&amp;gt;Hello, {name}&amp;lt;/h1&amp;gt;&quot;)  
    };
});

// register the Widgets endpoint from our class
router.SetObject(typeof(Widgets));
  
http.Start();  
Console.WriteLine($&quot;HTTP Server is listening on {http.ListeningPrefixes[0]}&quot;);  
Console.ReadKey();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we have a new endpoint in our application.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Sisk is a really exciting HTTP server, and while it’s certainly not the first attempt at an independent HTTP server implementation, it is a welcome addition to the .NET ecosystem. If you need a lightweight HTTP server implementation without all of what ASP.NET Core offers, then Sisk might be for you. Remember, though, this HTTP server is independent of the ASP.NET Core ecosystem, so be prepared to write your integrations or rely on external implementations.&lt;/p&gt;

&lt;p&gt;This post only begins to scratch the surface of what Sisk provides, so I suggest you check out the &lt;a href=&quot;https://github.com/sisk-http&quot;&gt;GitHub repository&lt;/a&gt; and &lt;a href=&quot;https://sisk.project-principium.dev/#/&quot;&gt;documentation&lt;/a&gt; to see if it’s right for you.&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/sisk-an-alternative-dotnet-http-server</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/sisk-an-alternative-dotnet-http-server</guid>
        
        <category>dotnet,</category>
        
        <category>aspnetcore</category>
        
        
      </item>
    
      <item>
        <title>.NET 8 Interceptors</title>
        <description>&lt;p&gt;Typically I wouldn’t say I like writing about preview features for multiple reasons. Most of my posts aim to help folks solve problems they might have rather than get on a soap box or advertise. But I thought I would cover this .NET preview feature as it’s a sister topic to something I’ve wanted in the .NET ecosystem for the longest time: monkey patching. If you’re unfamiliar with the topic, I suggest you read my post on monkey patching. In general, monkey patching allows you to substitute one implementation for another, and what do you know, &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/d71ec683082104e9122a4937abc768710c5f7782/docs/features/interceptors.md&quot;&gt;.NET 8 is introducing the concept of &lt;strong&gt;Interceptors&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As the name implies, Interceptors allow developers to target specific method invocations and intercept them with a new implementation. Interceptors have several purposes and meaningful distinctions that we’ll get into in this post. So let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-an-interceptor&quot;&gt;What is an Interceptor?&lt;/h2&gt;

&lt;p&gt;In .NET 8 preview 6, the SDK introduces additional functionality to “intercept” any method call within your codebase. The word “interceptor” is clear as to the purpose of this new functionality. It only replaces methods intentionally and does not replace method implementations globally. The approach means you, as the developer, must be systematic about using an Interceptor.&lt;/p&gt;

&lt;p&gt;The .NET team uses interceptors to overwrite infrastructure code that previously relied on reflection with compile-time versions specific to your application. Interceptors will hopefully reduce your programs’ start-up time and efficiency. The .NET team designed interceptors to work with source generators, as source generators can surgically deal with abstract syntax trees and code files to target method invocations. While you could hand-write interceptor calls, it becomes impractical in a real-world application.&lt;/p&gt;

&lt;p&gt;Let’s get into setting up your project to work with interceptors.&lt;/p&gt;

&lt;h2 id=&quot;getting-started-with-interceptors&quot;&gt;Getting Started with Interceptors&lt;/h2&gt;

&lt;p&gt;Interceptors are a .NET 8 preview 6 feature, so you’ll need the matching SDK version or higher to get this working. Begin by creating a new console application, or really any .NET application.&lt;/p&gt;

&lt;p&gt;Next, in your &lt;code&gt;.csproj&lt;/code&gt;, you must add the following &lt;code&gt;PropertyGroup&lt;/code&gt; element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PropertyGroup&amp;gt;
    &amp;lt;Features&amp;gt;InterceptorsPreview&amp;lt;/Features&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also be sure to set your &lt;code&gt;LangVersion&lt;/code&gt; element to &lt;code&gt;preview&lt;/code&gt; to get access to the feature.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PropertyGroup&amp;gt;
    &amp;lt;LangVersion&amp;gt;preview&amp;lt;/LangVersion&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, add the following attribute definition to your project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public sealed class InterceptsLocationAttribute : Attribute
{
    public InterceptsLocationAttribute(string filePath, int line, int character)
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, it’s weird that the attribute isn’t part of the BCL, but since this is a preview feature, I imagine the .NET team didn’t want to pollute the .NET framework with a potential API change later.&lt;/p&gt;

&lt;p&gt;You’ll notice that the attribute takes three parameters: &lt;strong&gt;filePath&lt;/strong&gt;, &lt;strong&gt;line&lt;/strong&gt;, and &lt;strong&gt;character&lt;/strong&gt;. You’ll also note that these values aren’t assigned anywhere, and you’d be correct. The attribute is a marker the compiler will read at compile-time, so setting the values for runtime use is pointless.&lt;/p&gt;

&lt;p&gt;Now, let’s intercept some code. Add the following to your &lt;code&gt;Program.cs&lt;/code&gt; file. &lt;strong&gt;Note, the line numbers and spacing are critically important. If you reformat the code, this solution might break.&lt;/strong&gt; Also be sure to change the file path to the absolute path of your &lt;code&gt;Program.cs&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Runtime.CompilerServices;

C.M(); // What the Fudge?!
C.M(); // Original

class C
{
    public static void M() =&amp;gt; Console.WriteLine(&quot;Original&quot;);
}

// generated
class D
{
    [InterceptsLocation(&quot;/Users/khalidabuhakmeh/RiderProjects/ConsoleApp12/ConsoleApp12/Program.cs&quot;, 
        line: 3, character: 3)]
    public static void M() =&amp;gt; Console.WriteLine(&quot;What the Fudge?!&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running the application above, you’ll see the most peculiar thing. Two different outputs from the same method call! What the heck?!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;What the Fudge?!
Original
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But how? What does the compiled code look like after compilation? We can see what happened using JetBrains Rider’s IL Viewer.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// Decompiled with JetBrains decompiler
// Type: Program
// Assembly: ConsoleApp12, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 09D7E1E0-5709-4A62-884A-AB84DAA1E08C
// Assembly location: /Users/khalidabuhakmeh/RiderProjects/ConsoleApp12/ConsoleApp12/bin/Debug/net8.0/ConsoleApp12.dll
// Local variable names from /users/khalidabuhakmeh/riderprojects/consoleapp12/consoleapp12/bin/debug/net8.0/consoleapp12.pdb
// Compiler-generated code is shown

using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void &amp;lt;Main&amp;gt;$(string[] args)
  {
    D.M();
    C.M();
  }

  public Program()
  {
    base..ctor();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can now see that the compiler replaced the first method invocation with our intercepting implementation. Wow!&lt;/p&gt;

&lt;p&gt;After the razzle-dazzle wears off, you’ll likely think this is impractical. Who has time to hardcode full paths to files, count lines, and count columns? Well, as mentioned previously, this is where source generators come in.&lt;/p&gt;

&lt;p&gt;While I won’t demonstrate it here when dealing with syntax trees, you do have access to information like &lt;code&gt;FilePath&lt;/code&gt;, and every &lt;code&gt;CSharpSyntaxNode&lt;/code&gt; has a &lt;code&gt;GetLocation&lt;/code&gt; method that gives you access to line numbers and location within a code file. If you’re already proficient in writing source generators, this information is already available.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This feature is definitely for a select group of individuals in the .NET community, specifically those who write and maintain source generators. Within that subgroup, you likely have framework authors looking to squeeze every last bit of performance out of .NET. As you’ve seen, Interceptors only change specific implementations and cannot target methods globally. If you’re using a source generator to do an interception of all methods, you’ll have to generate an interception call for each location. Generating a large amount of custom code can adversely affect the size of your compiled assets, so be aware of using this feature. Also, you may consider avoiding this feature altogether. Interceptors are still in preview, and the primary intention is to help .NET authors to improve ASP.NET Core and other frameworks within the .NET SDK. Either way, it’s good to understand this feature exists next time you’re debugging your .NET 8 applications because the method you think you’re calling might not be the method you’re actually calling.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this blog post, and as always, thanks for reading and sharing my posts with friends and colleagues.&lt;/p&gt;

</description>
        <pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dotnet-8-interceptors</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dotnet-8-interceptors</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Generate Sitemaps for All of ASP.NET Core</title>
        <description>&lt;p&gt;While ASP.NET Core is a robust web framework, it lacks some core features that make executing a creative-focused site more straightforward. One of those features is the ability to generate a sitemap. If folks can’t find your content, then for all intents and purposes, it doesn’t exist. Sitemaps tell search engines which parts of your site are essential for user searches.&lt;/p&gt;

&lt;p&gt;In this post, I’ll be combining an open-source project called &lt;a href=&quot;https://www.nuget.org/packages/DotnetSitemapGenerator&quot;&gt;DotnetSitemapGenerator&lt;/a&gt; with some of my custom infrastructure code to generate sitemap nodes from ASP.NET Core Minimal APIs, ASP.NET Core MVC actions, and Razor Pages. The post covers all the server-side rendered paradigms within ASP.NET Core, except for Blazor. As a bonus, I also generate sitemap nodes from a database using Entity Framework Core.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-a-sitemap&quot;&gt;What is a Sitemap?&lt;/h2&gt;

&lt;p&gt;A sitemap is a file provided by your web application that provides search engines with information about pages, videos, and other potential points of interest. Search engines use this file to crawl your site more efficiently, helping keep your search results up to date and more relevant for prospective visitors. A sitemap is typically hosted at the root of a website at &lt;code&gt;/sitemap.xml&lt;/code&gt; by convention but can be configured depending on your use case.&lt;/p&gt;

&lt;p&gt;While a sitemap is optional for a well-linked site, there are advantages to having one for your application.&lt;/p&gt;

&lt;p&gt;For instance, crawlers might have difficulty distinguishing between valuable pages if you have an extensive website. A large site can lead to issues indexing newer pages, and thus you may lose valuable visitors for more recent content.&lt;/p&gt;

&lt;p&gt;Newer sites might also struggle to have crawlers discover their existence, as fewer or no inbound links exist. Generating a sitemap and submitting it to popular search engines ensures your site finds its way quickly into the results of users. As your site becomes more popular, this is less likely a concern, but we all start somewhere.&lt;/p&gt;

&lt;p&gt;You may want search engines to index your rich media content separately from your written content. Having separate sitemaps can mean new avenues for users to discover your site. Sitemaps can clarify what value you are providing by creating distinctions between different types of content.&lt;/p&gt;

&lt;p&gt;While sitemaps can be helpful for many sites, they do not guarantee all items within your XML files will be indexed by search engines. That said, there are values for change frequency and priority that can help search engines prioritize their crawlers. Generally, it’s better to be safe than sorry when there’s so much competition for visitors.&lt;/p&gt;

&lt;h2 id=&quot;a-basic-sitemap&quot;&gt;A Basic Sitemap&lt;/h2&gt;

&lt;p&gt;Sitemaps, in their simplest form, are a collection of URLs. Let’s look at the final sample we’ll generate in this post.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;urlset xmlns=&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot;&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/test&amp;lt;/loc&amp;gt;
        &amp;lt;changefreq&amp;gt;daily&amp;lt;/changefreq&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/Privacy&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/cool/3&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/1/express-galaxy-tumbler&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/2/aero-life-air-purifier&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/3/ocean-wave-projector&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/4/illuminated-globe-decor&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/5/moonlight-cushion&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/6/sunrise-alarm-clock&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/7/frosty-mini-fridge&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/8/breeze-tower-fan&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/9/comet-electric-scooter&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;http://localhost:5077/products/10/starlight-projector&amp;lt;/loc&amp;gt;
    &amp;lt;/url&amp;gt;
&amp;lt;/urlset&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The XML file is presentationally unremarkable but essential to building an online presence.&lt;/p&gt;

&lt;p&gt;The XML file has endpoints from ASP.NET Core MVC controllers, Razor Pages, and Minimal APIs. Let’s look at how we register our Sitemap infrastructure, and then we’ll go through each mechanism that provides these values to our sitemap.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-aspnet-core-infrastructure&quot;&gt;Setting up the ASP.NET Core Infrastructure&lt;/h2&gt;

&lt;p&gt;We’ll start inside &lt;code&gt;Program.cs&lt;/code&gt; to see how all the pieces come together, then explore how we pull these nodes into our sitemap XML file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;
using Shopping.Models;
using Shopping.Sitemap;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddHttpContextAccessor();

// my unique extension method for sitemap information
builder.Services.AddSitemap();
builder.Services.AddOutputCache(options =&amp;gt; {
    options.AddPolicy(&quot;sitemap&quot;, b =&amp;gt; b.Expire(TimeSpan.FromSeconds(1)));
});

builder.Services.AddDbContext&amp;lt;Database&amp;gt;(
    ob =&amp;gt; ob.UseSqlite(&quot;Data Source = database.db&quot;)
);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(&quot;/Error&quot;);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseOutputCache();

app.MapSitemap().CacheOutput(&quot;sitemap&quot;);

app.MapGet(&quot;cool/{id}&quot;, () =&amp;gt; &quot;cool beans&quot;)
   .WithSitemap(&quot;cool&quot;, new { id = 3 });

app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We first start by adding our services to the ASP.NET Core services collection. The registrations include our sitemap providers, the Endpoints Api Explorer (for Minimal APIs), and the &lt;code&gt;HttpContextAccessor&lt;/code&gt; for generating links.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddEndpointsApiExplorer();
builder.Services.AddHttpContextAccessor();
// my unique extension method for sitemap information
builder.Services.AddSitemap();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Further down the file is our &lt;code&gt;sitemap.xml&lt;/code&gt; endpoint, enabling output caching.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapSitemap().CacheOutput(&quot;sitemap&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ve defined these methods in the project’s &lt;code&gt;SitemapExtensions.cs&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Shopping.Sitemap.Providers;

namespace Shopping.Sitemap;

public static class SitemapExtensions
{
    public static RouteHandlerBuilder MapSitemap(this IEndpointRouteBuilder endpoints, string path = &quot;sitemap.xml&quot;)
    {
        return endpoints.MapGet(path, async (SitemapBuilder sitemap) =&amp;gt;
        {
            var xml = await sitemap.GenerateAsync();
            return Results.Stream(xml, &quot;text/xml&quot;);
        });
    }

    public static void AddSitemap(this IServiceCollection services)
    {
        // add sitemap services
        services.AddScoped&amp;lt;ISitemapUrlProvider, PagesSitemapUrlProvider&amp;gt;();
        services.AddScoped&amp;lt;ISitemapUrlProvider, EndpointsSitemapUrlProvider&amp;gt;();
        services.AddScoped&amp;lt;ISitemapUrlProvider, ProductSitemapSitemapUrlProvider&amp;gt;();
        services.AddScoped&amp;lt;SitemapBuilder&amp;gt;();
    }

    public static RouteHandlerBuilder WithSitemap(this RouteHandlerBuilder endpoint,
        string name, object? defaults = null)
    {
        return endpoint
            // adds RouteName and EndpointName
            .WithName(name)
            .WithMetadata(new SitemapAttribute
            {
                RouteValues = new RouteValueDictionary(defaults)
            });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;AddSiteMap&lt;/code&gt; method registers our URL providers, which will ultimately be used by our &lt;code&gt;SitemapBuilder&lt;/code&gt; to combine all the nodes for our &lt;code&gt;sitemap.xml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now that we have infrastructure covered let’s talk about each ASP.NET Core approach your endpoints may be implemented in.&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-razor-pages-and-mvc-actions&quot;&gt;ASP.NET Core Razor Pages and MVC Actions&lt;/h2&gt;

&lt;p&gt;Razor Pages and MVC Views are considered Actions in ASP.NET Core, so they behave very similarly within the context of sitemap generation. The only difference between the two approaches is how you generate links from each route.&lt;/p&gt;

&lt;p&gt;Let’s look at our &lt;code&gt;PagesSitemapUrlProvider&lt;/code&gt;, which will support MVC and Razor Pages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using DotnetSitemapGenerator;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using IsRazorPage = Microsoft.AspNetCore.Mvc.RazorPages.CompiledPageActionDescriptor;
using IsMvc = Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;

namespace Shopping.Sitemap.Providers;

public class PagesSitemapUrlProvider : ISitemapUrlProvider
{
    private readonly LinkGenerator _linkGenerator;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
    private readonly ILogger&amp;lt;PagesSitemapUrlProvider&amp;gt; _logger;

    public PagesSitemapUrlProvider(
        LinkGenerator linkGenerator,
        IHttpContextAccessor httpContextAccessor,
        IActionDescriptorCollectionProvider actionDescriptorCollectionProvider,
        ILogger&amp;lt;PagesSitemapUrlProvider&amp;gt; logger)
    {
        _linkGenerator = linkGenerator;
        _httpContextAccessor = httpContextAccessor;
        _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
        _logger = logger;
    }

    public Task&amp;lt;IReadOnlyCollection&amp;lt;SitemapNode&amp;gt;&amp;gt; GetNodes()
    {
        var httpContext = _httpContextAccessor.HttpContext!;
        var nodes = new List&amp;lt;SitemapNode&amp;gt;();

        foreach (var descriptor in _actionDescriptorCollectionProvider.ActionDescriptors.Items)
        {
            // LastOrDefault is used to get the closest SitemapAttribute to the endpoint
            var exists = descriptor.EndpointMetadata.LastOrDefault(em =&amp;gt; em is SitemapAttribute); 
            if (exists is not SitemapAttribute sitemapAttribute) continue;
            
            var url = descriptor switch
            {
                // Razor Pages
                IsRazorPage razorPage =&amp;gt;
                    _linkGenerator.GetUriByPage(httpContext, page: razorPage.ViewEnginePath),
                // ASP.NET Core MVC
                IsMvc controller =&amp;gt;
                    _linkGenerator.GetUriByAction(httpContext,
                        action: controller.ActionName,
                        controller: controller.ControllerName,
                        // use the values provided by the user (if any)
                        values: sitemapAttribute.RouteValues),
                _ =&amp;gt; null
            };

            if (ShouldAddUrl(nodes, url))
            {
                nodes.Add(new SitemapNode(url)
                {
                    ChangeFrequency = sitemapAttribute.ChangeFrequency,
                    Priority = sitemapAttribute.Priority
                });
            }
        }

        return Task.FromResult&amp;lt;IReadOnlyCollection&amp;lt;SitemapNode&amp;gt;&amp;gt;(nodes);
    }
    
    private static bool ShouldAddUrl(List&amp;lt;SitemapNode&amp;gt; nodes, string? url)
    {
        // if the url failed to generate, don&apos;t add a record
        if (string.IsNullOrWhiteSpace(url)) return false;
        // if it already exists based on the URL, don&apos;t add it
        return !nodes.Exists(n =&amp;gt; n.Url.Equals(url, StringComparison.OrdinalIgnoreCase));
    }
    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The trick in this method is utilizing the information from &lt;code&gt;ActionDescriptor&lt;/code&gt; to determine how we want to generate links using the &lt;code&gt;LinkGenerator&lt;/code&gt; instance. We also require an &lt;code&gt;HttpContext&lt;/code&gt; to determine values for the base URL.&lt;/p&gt;

&lt;p&gt;Now all we need to do is decorate the endpoints we want to include in our Sitemap generation process. Here’s an example using custom attributes on our controller, where the closest attribute will be used when creating the sitemap node.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc;
using Shopping.Sitemap;

namespace Shopping.Controllers;

[ControllerSitemap]
public class TestController : Controller
{
    [ActionSitemap]
    [Route(&quot;test&quot;)]
    public IActionResult Index()
    {
        return View();
    }
}

public class ControllerSitemapAttribute : SitemapAttribute
{
}

public class ActionSitemapAttribute : SitemapAttribute
{
    public ActionSitemapAttribute()
    {
        ChangeFrequency = DotnetSitemapGenerator.ChangeFrequency.Daily;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The implementation in Razor Pages is similar, but here we use the base &lt;code&gt;SitemapAttribute&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Shopping.Models;
using Shopping.Sitemap;

namespace Shopping.Pages;

[Sitemap]
public class IndexModel : PageModel
{
    private readonly ILogger&amp;lt;IndexModel&amp;gt; _logger;
    private readonly Database _db;

    public IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger, Database db)
    {
        _logger = logger;
        _db = db;
    }

    public List&amp;lt;Product&amp;gt; Products { get; set; } = new();

    public async Task OnGet()
    {
        Products = await _db
            .Products
            .OrderBy(p =&amp;gt; p.Id)
            .ToListAsync();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! What about Minimal API endpoints?&lt;/p&gt;

&lt;h2 id=&quot;aspnet-core-minimal-api-endpoints&quot;&gt;ASP.NET Core Minimal API endpoints&lt;/h2&gt;

&lt;p&gt;While most developers use ASP.NET Core Minimal APIs for API endpoints that return JSON or XML, developers may also choose to return any content type, which may include HTML files. So you may find these endpoints straddling the line between API and presentational duties.&lt;/p&gt;

&lt;p&gt;For completeness, let’s add an option for Minimal API endpoints.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using DotnetSitemapGenerator;
using Microsoft.AspNetCore.Mvc.ApiExplorer;

namespace Shopping.Sitemap.Providers;

public class EndpointsSitemapUrlProvider : ISitemapUrlProvider
{
    private readonly LinkGenerator _linkGenerator;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionGroupCollectionProvider;
    private readonly ILogger&amp;lt;PagesSitemapUrlProvider&amp;gt; _logger;

    public EndpointsSitemapUrlProvider(
        LinkGenerator linkGenerator,
        IHttpContextAccessor httpContextAccessor,
        IApiDescriptionGroupCollectionProvider apiDescriptionGroupCollectionProvider,
        ILogger&amp;lt;PagesSitemapUrlProvider&amp;gt; logger)
    {
        _linkGenerator = linkGenerator;
        _httpContextAccessor = httpContextAccessor;
        _apiDescriptionGroupCollectionProvider = apiDescriptionGroupCollectionProvider;
        _logger = logger;
    }

    public Task&amp;lt;IReadOnlyCollection&amp;lt;SitemapNode&amp;gt;&amp;gt; GetNodes()
    {
        var httpContext = _httpContextAccessor.HttpContext!;
        var nodes = new List&amp;lt;SitemapNode&amp;gt;();

        // Minimal Apis that might return HTML
        foreach (var group in _apiDescriptionGroupCollectionProvider.ApiDescriptionGroups.Items)
        {
            var endpoints =
                group
                    .Items
                    .Where(i =&amp;gt; HttpMethods.IsGet(i.HttpMethod ?? &quot;&quot;))
                    .Where(i =&amp;gt; i.ActionDescriptor.EndpointMetadata.Any(em =&amp;gt; em is SitemapAttribute));

            foreach (var endpoint in endpoints)
            {
                var attribute = endpoint
                    .ActionDescriptor
                    .EndpointMetadata
                    .LastOrDefault(a =&amp;gt; a is SitemapAttribute);

                if (attribute is not SitemapAttribute sitemapAttribute)
                    continue;

                var routeName = endpoint
                    .ActionDescriptor
                    .EndpointMetadata
                    .Where(m =&amp;gt; m is RouteNameMetadata)
                    .Cast&amp;lt;RouteNameMetadata&amp;gt;()
                    .Select(a =&amp;gt; a.RouteName)
                    .FirstOrDefault();

                if (routeName is null)
                    continue;

                var url = _linkGenerator.GetUriByName(
                    httpContext,
                    routeName,
                    values: sitemapAttribute.RouteValues
                );

                if (ShouldAddUrl(nodes, url))
                {
                    nodes.Add(new SitemapNode(url)
                    {
                        ChangeFrequency = sitemapAttribute.ChangeFrequency,
                        Priority = sitemapAttribute.Priority
                    });
                }
            }
        }

        return Task.FromResult&amp;lt;IReadOnlyCollection&amp;lt;SitemapNode&amp;gt;&amp;gt;(nodes);
    }

    private static bool ShouldAddUrl(List&amp;lt;SitemapNode&amp;gt; nodes, string? url)
    {
        // if the url failed to generate, don&apos;t add a record
        if (string.IsNullOrWhiteSpace(url)) return false;
        // if it already exists based on the URL, don&apos;t add it
        return !nodes.Exists(n =&amp;gt; n.Url.Equals(url, StringComparison.OrdinalIgnoreCase));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll need to annotate our API endpoints to get Minimal API endpoints into the sitemap.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;cool/{id}&quot;, () =&amp;gt; &quot;cool beans&quot;)
   .WithSitemap(&quot;cool&quot;, new { id = 3 });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, we have a route value that needs to be satisfied before generating the link. Using the &lt;code&gt;WithSitemap&lt;/code&gt; method, we can provide a default value. The extension method also adds a name to our endpoint metadata, which allows us to generate the correct link.&lt;/p&gt;

&lt;p&gt;We’re on a roll. What about data-driven pages?&lt;/p&gt;

&lt;h2 id=&quot;database-driven-pages-with-entity-framework-core&quot;&gt;Database-driven pages with Entity Framework Core&lt;/h2&gt;

&lt;p&gt;Many sites have dynamic pages built on a dataset. Dynamic URLs are standard on shopping sites with an extensive product catalog. Let’s see how we can implement a &lt;code&gt;ProductSitemapUrlProvider&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using DotnetSitemapGenerator;
using Microsoft.EntityFrameworkCore;
using Shopping.Models;

namespace Shopping.Sitemap.Providers;

public class ProductSitemapSitemapUrlProvider : ISitemapUrlProvider
{
    private readonly Database _db;
    private readonly LinkGenerator _linkGenerator;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ProductSitemapSitemapUrlProvider(
        Database db, 
        LinkGenerator linkGenerator, 
        IHttpContextAccessor httpContextAccessor)
    {
        _db = db;
        _linkGenerator = linkGenerator;
        _httpContextAccessor = httpContextAccessor;
    }
    
    public async Task&amp;lt;IReadOnlyCollection&amp;lt;SitemapNode&amp;gt;&amp;gt; GetNodes()
    {
        var elements = new List&amp;lt;SitemapNode&amp;gt;();
        var products = await _db.Products.OrderBy(x =&amp;gt; x.Id).ToListAsync();
        
        foreach (var product in products)
        {
            var url = _linkGenerator.GetUriByPage(
                _httpContextAccessor.HttpContext!,
                page: &quot;/Products&quot;,
                values: new { product.Id, product.Slug });
            
            elements.Add(new SitemapNode(url));
        }

        return elements;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s pretty straightforward. We must point to our product detail page, a Razor page at &lt;code&gt;/Products&lt;/code&gt;, and get a unique URL for each product.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/AspNetCore-Sitemap&quot;&gt;Working sample at GitHub repository for ASP.NET Core Sitemap&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With some help from an OSS project, I created a robust framework for generating sitemaps in ASP.NET Core using different programming approaches. While I’m sure this approach has more room for improvement, I’m pretty happy with the final result. What do you think?&lt;/p&gt;

&lt;p&gt;I added this project to GitHub, and I don’t intend to make it a NuGet package soon since I see developers adapting the code for each project. If you’re inspired to make it a NuGet package, you can do so; just let me know.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing my posts with friends and colleagues.&lt;/p&gt;

</description>
        <pubDate>Tue, 01 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/generate-sitemaps-for-all-of-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/generate-sitemaps-for-all-of-aspnet-core</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>.NET 8 TimeProvider and Unit Tests</title>
        <description>&lt;p&gt;Working with time has always been one of the more difficult parts of software development. Inevitably, time makes fools of us all. Luckily, for .NET 8 users, there’s a new attempt to provide tools to make testing your time-based logic much more straightforward.&lt;/p&gt;

&lt;p&gt;This post explores the new .NET 8 packages of &lt;code&gt;Microsoft.Bcl.TimerProvider&lt;/code&gt; and its testing partner of &lt;code&gt;Microsoft.Extensions.TimeProvider.Testing&lt;/code&gt;. Specifically, we’ll see how to access controlled values for &lt;code&gt;Now&lt;/code&gt; and &lt;code&gt;UtcNow&lt;/code&gt; and how to tick a timer into the future, all through the use of &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.timeprovider?view=net-8.0&quot;&gt;&lt;code&gt;TimeProvider&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-use-a-time-provider&quot;&gt;Why use a Time Provider?&lt;/h2&gt;

&lt;p&gt;We’ve all been there, writing business logic that relies on the passage of time. “Execute this method a minute from now, but only if it’s a Monday!” Personally, the challenge of dealing with Date and Time elements in code can be a herculean effort. The packages shipped in .NET 8 attempt to give developers access to a &lt;code&gt;TimeProvider&lt;/code&gt; abstraction with methods like &lt;code&gt;GetUtcNow&lt;/code&gt;, &lt;code&gt;GetLocalNow&lt;/code&gt;, &lt;code&gt;GetTimestamp&lt;/code&gt;, and others. These methods provide instances of the &lt;code&gt;DateTimeOffset&lt;/code&gt; class, which inherits from &lt;code&gt;DateTime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition to Date and Time helpers, the &lt;code&gt;TimeProvider&lt;/code&gt; class provides mechanisms to create &lt;code&gt;Timer&lt;/code&gt; instances. In the default implementation, the timer created is of type &lt;code&gt;SystemTimeProviderTimer&lt;/code&gt; and implements the &lt;code&gt;ITimer&lt;/code&gt; interface. Having the timer instance originate from the &lt;code&gt;TimeProvider&lt;/code&gt; allows the testing package to implement a test instance for unit testing.&lt;/p&gt;

&lt;p&gt;This layer of indirection allows you to be a time lord, controlling when clocks tick forward, move backward, and when timers should get called. The power to change time can help you test the trickiest of time-based code.&lt;/p&gt;

&lt;p&gt;Let’s see a few examples.&lt;/p&gt;

&lt;h2 id=&quot;using-the-testing-classes&quot;&gt;Using The Testing Classes&lt;/h2&gt;

&lt;p&gt;In your codebase, you’re likely to take a dependency on &lt;code&gt;TimeProvider&lt;/code&gt;, but in your tests, you’ll be substituting an instance of &lt;code&gt;FakeTimeProvider&lt;/code&gt;. It’s a fake time provider.&lt;/p&gt;

&lt;p&gt;In my contrived example, I’ve created a method that finds the next day of the week.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class DateTimeExtensions
{
    public static DateTime FindNext(this TimeProvider provider, DayOfWeek dayOfWeek)
    {
        var now = provider.GetLocalNow();
        var daysUntilNextWeekDay = ((int)dayOfWeek - (int)now.DayOfWeek + 7) % 7;
        return now.DateTime.AddDays(daysUntilNextWeekDay);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note: Yes, this is a contrived example. I could have passed the &lt;code&gt;DateTime&lt;/code&gt; to the method, but that’s not the point.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s create a &lt;code&gt;FakeTimeProvider&lt;/code&gt; and set the current date and time.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[Fact]
public void Can_Find_Next_Monday()
{
    var fake = new FakeTimeProvider();
 
    //This is a Wednesday
    fake.SetUtcNow(DateTime.Parse(&quot;2023-06-28&quot;));

    var result = fake.FindNext(DayOfWeek.Monday);
    
    Assert.Equal(&quot;2023-07-03&quot;, result.ToString(&quot;yyyy-MM-dd&quot;));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Great! That was easy. You must create a new &lt;code&gt;FakeTimeProvider&lt;/code&gt; for each appropriate scope. One per test is the safest, but I can also see folks creating one provider for a group of tests. Use your judgment here.&lt;/p&gt;

&lt;p&gt;What about Timers? Fake timers use the &lt;code&gt;FakeTimeProvider&lt;/code&gt; to know the elapsed time and determine when they should fire. Using the &lt;code&gt;TimeProvider&lt;/code&gt; abstraction is helpful for testing callbacks and the infrastructure you may create to manage timers. Let’s look at a complete timer test.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[Fact]
public void Can_tick_when_asked()
{
    var fake = new FakeTimeProvider();
    var now = DateTime.Now;
    fake.SetUtcNow(now);
    
    var result = false;
    
    fake.CreateTimer(
        _ =&amp;gt; result = !result,
        state: null, 
        // time to delay before invoking the callback method
        // if TimeSpan.Zero will get immediately invoked
        dueTime: TimeSpan.FromSeconds(1),
        // time between callback invocations
        period: TimeSpan.FromMinutes(1)
    );
    
    Assert.False(result);
    
    // Change the fabric of space &amp;amp; time...
    // well not really.
    fake.SetUtcNow(now.AddMinutes(1));
    
    Assert.True(result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The previous code creates a timer, but we only execute the callback when the time is set a minute into the future. Now we can test our callbacks and if they work as expected with a few lines of code. &lt;strong&gt;The &lt;code&gt;dueTime&lt;/code&gt; argument is essential, as setting it to &lt;code&gt;TimeSpan.Zero&lt;/code&gt; will fire the callback immediately.&lt;/strong&gt; This behavior may be what you want, but it also means you have no opportunity to test the prior state of your tests.&lt;/p&gt;

&lt;p&gt;Here’s the complete unit test to play around with the packages and classes yourself.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Extensions.Time.Testing;

public class UnitTest1
{
    [Fact]
    public void Can_Find_Next_Monday()
    {
        var fake = new FakeTimeProvider();
     
        // this is a Wednesday
        fake.SetUtcNow(DateTime.Parse(&quot;2023-06-28&quot;));
        
        var result = fake.FindNext(DayOfWeek.Monday);
        
        Assert.Equal(&quot;2023-07-03&quot;, result.ToString(&quot;yyyy-MM-dd&quot;));
    }

    [Fact]
    public void Current_Day_Of_Week_Counts_As_Next()
    {
        var fake = new FakeTimeProvider();
     
        // this is a Wednesday
        fake.SetUtcNow(DateTime.Parse(&quot;2023-06-28&quot;));

        var result = fake.FindNext(DayOfWeek.Wednesday);
        
        Assert.Equal(&quot;2023-06-28&quot;, result.ToString(&quot;yyyy-MM-dd&quot;));
    }

    [Fact]
    public void Can_tick_when_asked()
    {
        var fake = new FakeTimeProvider();
        var now = DateTime.Now;
        fake.SetUtcNow(now);
        
        var result = false;
        
        fake.CreateTimer(
            _ =&amp;gt; result = !result,
            state: null, 
            // time to delay before invoking the callback method
            // if TimeSpan.Zero will get immediately invoked
            dueTime: TimeSpan.FromSeconds(1),
            // time between callback invocations
            period: TimeSpan.FromMinutes(1)
        );
        
        Assert.False(result);
        
        // Change the fabric of space &amp;amp; time...
        // well not really.
        fake.SetUtcNow(now.AddMinutes(1));
        
        Assert.True(result);
    }
    
}

public static class DateTimeExtensions
{
    public static DateTime FindNext(this TimeProvider provider, DayOfWeek dayOfWeek)
    {
        var now = provider.GetLocalNow();
        var daysUntilNextWeekDay = ((int)dayOfWeek - (int)now.DayOfWeek + 7) % 7;
        return now.DateTime.AddDays(daysUntilNextWeekDay);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The new &lt;code&gt;Microsoft.Bcl.TimeProvider&lt;/code&gt; package and the &lt;code&gt;TimeProvider&lt;/code&gt; abstraction should help folks add a layer of separation between them and the &lt;code&gt;DateTime&lt;/code&gt; model of .NET. These new classes should alleviate the tight coupling between your business logic and the forward march of time, helping increase the reliability of your codebase. I hope you found this post interesting. Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dotnet-8-timeprovider-and-unit-tests</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dotnet-8-timeprovider-and-unit-tests</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>C# Records, the With Keyword, and Reference Types</title>
        <description>&lt;p&gt;The &lt;code&gt;record&lt;/code&gt; keyword in C# has been available since C# 9, and you either love it or hate it. Regardless of your opinion, you will likely make a not-so-obvious mistake when working with the &lt;code&gt;with&lt;/code&gt; keyword. This particular mistake can lead to strange system behavior and hard-to-diagnose bugs. Nobody wants bugs, right?!&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore the problem and how to solve that issue.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-problem-with-records&quot;&gt;The Problem with Records&lt;/h2&gt;

&lt;p&gt;The virtue of &lt;code&gt;record&lt;/code&gt; types is based on immutability, allowing you, the developer, to encapsulate data and pass it around without fear of introducing unwanted changes. The &lt;code&gt;with&lt;/code&gt; keyword enables you to copy an existing record to avoid mutating the original value, thus maintaining a clear separation between what was and might be. Let’s take a look at a simple example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var one = new Simple(1);
var copy = one with { Number = one.Number + 1 };

Console.WriteLine(copy);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When running the previous code, the result is the following console output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Simple { Number = 2 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Attempting to change the &lt;code&gt;Number&lt;/code&gt; directly creates a compilation exception with the message.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Init-only property &apos;Simple.Number&apos; can only be assigned in an object initializer, or on &apos;this&apos; or &apos;base&apos; in an instance constructor or an &apos;init&apos; accessor
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, the real fun begins. We’ve been looking at value types, which the runtime will copy. What about reference types? Let’s add a collection to a record.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var item = new Item();

var newItem = item with { };
item.State.Add(1);
newItem.State.Add(2);

Console.WriteLine(item);
Console.WriteLine(newItem);

public record Item(List&amp;lt;int&amp;gt; State)
{
    public Item() : this(new List&amp;lt;int&amp;gt;())
    {
    }

    public override string ToString()
    {
        return $&quot;Item {{ State = {string.Join(&quot;, &quot;, State)} }}&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What do you expect &lt;code&gt;State&lt;/code&gt; (don’t peek)? You would be correct if you guessed it would be &lt;code&gt;1, 2&lt;/code&gt; across both instances.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Item { State = 1, 2 }
Item { State = 1, 2 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you may well know, reference types point to a location in memory. When using the &lt;code&gt;with&lt;/code&gt; keyword on records with reference types, the runtime will copy the reference to the new instance of the record. This behavior is excellent for memory efficiency, as the runtime does not allocate more memory for read-only information. This behavior is not good if you mutate the data before passing the data around to other consumers.&lt;/p&gt;

&lt;p&gt;How do we solve this issue? Well, there are two ways.&lt;/p&gt;

&lt;h2 id=&quot;using-property-setters-when-copying&quot;&gt;Using Property Setters when copying&lt;/h2&gt;

&lt;p&gt;The first approach is to be aware of all the reference types in a record and mutate the values early in the creation process.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var item = new Item();

var newItem = item with { State = item.State.Append(2).ToList() };
item.State.Add(1);

Console.WriteLine(item);
Console.WriteLine(newItem);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The resulting output shows we now have two different collections.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Item { State = 1 }
Item { State = 2 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This approach is acceptable but requires effort when using the &lt;code&gt;with&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;Another approach is using a “copy constructor”. A copy constructor is a method that takes an instance in the known inheritance hierarchy and allows you to make decisions during the creation process. Let’s change our record definition by adding a copy constructor that creates a new collection instance. &lt;strong&gt;The &lt;code&gt;with&lt;/code&gt; keyword will tell the runtime to look for a copy constructor on your definition before copying values over.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var item = new Item();

var newItem = item with { };
item.State.Add(1);
newItem.State.Add(2);
Console.WriteLine(item);
Console.WriteLine(newItem);

public record Item(List&amp;lt;int&amp;gt; State)
{
    public Item() : this(new List&amp;lt;int&amp;gt;())
    {
    }

    // copy constructor
    protected Item(Item oldItem)
    {
        State = new List&amp;lt;int&amp;gt;(oldItem.State);
    }

    public override string ToString()
    {
        return $&quot;Item {{ State = {string.Join(&quot;, &quot;, State)} }}&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we run the previous code, our result shows two separate collections on two record instances.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Item { State = 1 }
Item { State = 2 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You have two viable approaches to work around reference types in &lt;code&gt;record&lt;/code&gt; types.&lt;/p&gt;

&lt;p&gt;Another option you should consider is the use of immutable reference types from the start. In the case of this example, you may want to use &lt;code&gt;IReadOnlyList&lt;/code&gt; instead of &lt;code&gt;List&lt;/code&gt; right in the record’s constructor.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While the &lt;code&gt;record&lt;/code&gt; type has syntactic significance in C#, under the covers, it’s just a specialized implementation of a &lt;code&gt;class&lt;/code&gt;. The concepts around value types and reference types still apply. Remembering what values you add to your implementations is essential, as incorrectly copying records can lead to strange bugs. My recommendation to most folks using &lt;code&gt;record&lt;/code&gt; types would be to implement the copy constructor early on to remember to be intentional about the copying process.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and thank you for sharing this post with friends and colleagues. Cheers :)&lt;/p&gt;

</description>
        <pubDate>Tue, 18 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/csharp-records-the-with-keyword-and-reference-types</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/csharp-records-the-with-keyword-and-reference-types</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>HTMX, ASP.NET Core, and Bootstrap Modals</title>
        <description>&lt;p&gt;If you’ve done any frontend development in the past decade, you’ve likely interacted with Bootstrap, a toolkit focused on providing developers with CSS layout rules and components. Additionally, no frontend toolkit is complete with the accompanying JavaScript to make components interactive. That said, the JavaScript aspects are entirely optional, and the toolkit has a “Bring Your Own JavaScript” philosophy to integrate Bootstrap visual components into whatever frontend library you choose.&lt;/p&gt;

&lt;p&gt;This post will show how to use &lt;a href=&quot;https://getboostrap.com&quot;&gt;Bootstrap&lt;/a&gt; modals with &lt;a href=&quot;https://htxm.org&quot;&gt;HTMX&lt;/a&gt;. For folks who aren’t aware, HTMX is a hypermedia-focused library to build interactivity into your client applications with server-rendered responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please note I’m using the &lt;a href=&quot;https://github.com/khalidabuhakmeh/Htmx.Net&quot;&gt;HTMX.NET&lt;/a&gt; library and ASP.NET Core tag helpers.&lt;/strong&gt;&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;bootstrap-modals&quot;&gt;Bootstrap Modals&lt;/h2&gt;

&lt;p&gt;Bootstrap modals are built with HTML, CSS, and Javascript in mind. You typically have all three working together to get the intended behavior the Bootstrap team intended. You can find these interactive portions of bootstrap modals in the JavaScript library that accompanies the library, but there’s a caveat.&lt;/p&gt;

&lt;p&gt;Modals have to already exist on the page as HTML or programmatically added through JavaScript calls. Static modals are great, but likely not what most folks want. Most developers want dynamic modals based on user interaction or situational modals. So how do we get dynamic modals that we generate on the server? Well, spoiler alert, HTMX, of course!&lt;/p&gt;

&lt;h2 id=&quot;htmx-and-all-that-jazz&quot;&gt;HTMX and All That Jazz&lt;/h2&gt;

&lt;p&gt;Before we start looking at the code, let’s look at the parts of the process we need to consider.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The interactive element is a button a user will click to trigger a request to the server.&lt;/li&gt;
  &lt;li&gt;The endpoint that receives and renders the modal.&lt;/li&gt;
  &lt;li&gt;The endpoint that receives and responds with a user-specific response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re a backend developer, implementing these steps will get you the intended behavior, and it’s all straightforward. Let’s walk through implementing each.&lt;/p&gt;

&lt;h3 id=&quot;the-modal-trigger&quot;&gt;The Modal Trigger&lt;/h3&gt;

&lt;p&gt;Modals need a trigger and a target. When our user clicks the trigger, we want to request the server to generate and return our modal HTML.&lt;/p&gt;

&lt;p&gt;Let’s start with our button and what HTMX attributes we’ll need. I use ASP.NET Core Razor Pages, which works with any backend technology. Also, remember some of these attributes are part of the HTMX.NET library and the tag helpers it provides.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;@page
@model IndexModel
@{
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;
}

&amp;lt;div class=&quot;text-center&quot;&amp;gt;
    &amp;lt;h1 class=&quot;display-4&quot;&amp;gt;Welcome&amp;lt;/h1&amp;gt;
    &amp;lt;button hx-get hx-page=&quot;Index&quot; 
            hx-page-handler=&quot;Modal&quot;
            hx-target=&quot;#modal-container&quot;&amp;gt;
        Show Modal
    &amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div id=&quot;modal-container&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Razor Pages handler is a simple endpoint that returns an &lt;code&gt;IActionResult&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public IActionResult OnGetModal()
{
    return Partial(&quot;Modal&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now that we have that part let’s look at the modal HTML itself.&lt;/p&gt;

&lt;h3 id=&quot;the-server-rendered-modal&quot;&gt;The Server-rendered Modal&lt;/h3&gt;

&lt;p&gt;The modal is your run-of-the-mill Bootstrap modal but with some additional JavaScript. Here is the trick. &lt;strong&gt;HTMX will execute any &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; elements immediately, allowing you to perform the necessary setup for HTML&lt;/strong&gt;. The behavior will enable you to use HTMX and the JavaScript the Bootstrap development team intended.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;@model IndexModel

&amp;lt;div id=&quot;my-modal&quot; class=&quot;modal fade&quot; tabindex=&quot;-1&quot;&amp;gt;
    &amp;lt;div class=&quot;modal-dialog modal-dialog-centered&quot;&amp;gt;
        &amp;lt;div id=&quot;modal-body&quot; class=&quot;modal-content&quot;&amp;gt;
            &amp;lt;div class=&quot;modal-header&quot;&amp;gt;
                &amp;lt;h5 class=&quot;modal-title&quot;&amp;gt;From The Server&amp;lt;/h5&amp;gt;
                &amp;lt;button type=&quot;button&quot;
                        class=&quot;btn-close&quot;
                        data-bs-dismiss=&quot;modal&quot;
                        aria-label=&quot;Close&quot;&amp;gt;
                &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;modal-body&quot;&amp;gt;
                &amp;lt;form id=&quot;myForm&quot; hx-post
                      hx-page=&quot;index&quot;
                      hx-page-handler=&quot;Modal&quot;
                      hx-target=&quot;closest .modal-body&quot;&amp;gt;
                    &amp;lt;div class=&quot;mb-3&quot;&amp;gt;
                        &amp;lt;label asp-for=&quot;Message&quot; class=&quot;form-label&quot;&amp;gt;&amp;lt;/label&amp;gt;
                        &amp;lt;input asp-for=&quot;Message&quot; class=&quot;form-control&quot; placeholder=&quot;Your message...&quot;&amp;gt;
                    &amp;lt;/div&amp;gt;
                    @Html.AntiForgeryToken()
                &amp;lt;/form&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;modal-footer&quot;&amp;gt;
                &amp;lt;button form=&quot;myForm&quot;
                        type=&quot;submit&quot;
                        class=&quot;btn btn-primary&quot;&amp;gt;
                    Save changes
                &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
    function showModal() {
        const modal = new bootstrap.Modal(&apos;#my-modal&apos;);
        modal.show();
    }
    // scopes the modal so we can keep creating them
    showModal();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking through the HTML, you’ll see HTMX attributes sprinkled throughout. HTMX will process these attributes as it adds the HTML clientside DOM. I’m using HTMX’s &lt;code&gt;hx-target&lt;/code&gt; to tell HTMX where the following response should go. Please read the HTMX documentation to understand how to use &lt;code&gt;hx&lt;/code&gt; attributes for your solutions.&lt;/p&gt;

&lt;p&gt;If you have a message-only modal, you can stop here, but if you need modals for further interactions, the next section will show you how to handle that use case.&lt;/p&gt;

&lt;p&gt;OK, one more step: we’ll have an interactive HTMX-powered modal.&lt;/p&gt;

&lt;h3 id=&quot;the-form-submission&quot;&gt;The Form Submission&lt;/h3&gt;

&lt;p&gt;We must receive the HTML form’s input elements in our Razor Pages handler. In the sample above, that is a single &lt;code&gt;Message&lt;/code&gt; text box. Our Razor Page implementation has an endpoint and a &lt;code&gt;string&lt;/code&gt; property.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[BindProperty]
public string? Message { get; set; }

public IActionResult OnPostModal()
{
    return Partial(&quot;Success&quot;, this);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Along with the C# code, we have a corresponding view of &lt;code&gt;Success&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;@model IndexModel

&amp;lt;strong&amp;gt;You Said: &quot;@Model.Message&quot;&amp;lt;/strong&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow, that’s it.&lt;/p&gt;

&lt;p&gt;If you’d like to see a complete working version of this solution, you can get &lt;a href=&quot;https://github.com/khalidabuhakmeh/HtmxBootstrapModal&quot;&gt;the working HTMX Bootstrap modal sample on my GitHub Repository here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Bootstrap is a popular frontend library designed to allow you to bring any client-side libraries to the party. In my case, I enjoy using HTMX to enhance an otherwise static experience. As you can see in the sample, it only takes some basic problem-solving skills to bring the two together.&lt;/p&gt;

&lt;p&gt;I hope you found this blog post helpful, and thank you for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 11 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/htmx-aspnet-core-and-bootstrap-modals</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/htmx-aspnet-core-and-bootstrap-modals</guid>
        
        <category>htmx,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Adding a Readme to NuGet Package Landing Pages</title>
        <description>&lt;p&gt;An essential part of working on open-source libraries is conveying the value and useability of said library—a well-written “readme” file, while not a substitute for complete documentation, can help onboard new users and increase the joy of using your code.&lt;/p&gt;

&lt;p&gt;Regarding NuGet packages, you can now add a &lt;code&gt;Readme.md&lt;/code&gt; asset to your NuGet packages, which NuGet.org will display on your package’s landing page, thus giving you another medium to attract new users and inform the curious developer. For example, check out my library &lt;a href=&quot;https://www.nuget.org/packages/Htmx.TagHelpers/1.1.3#readme-body-tab&quot;&gt;HTMX.NET landing page&lt;/a&gt;, which now has the read me prominently displayed.&lt;/p&gt;

&lt;p&gt;Let’s see what steps you must take to accomplish the same in your libraries.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-readme-file&quot;&gt;The Readme File&lt;/h2&gt;

&lt;p&gt;Typically, at the root of every open-source repository should be a &lt;code&gt;readme.md&lt;/code&gt; file. The inclusion of the file has become a convention across GitHub, GitLab, and most distributed source control offerings. Your source control’s user interface will display the readme to repository visitors, allowing them to read your perspective and introductory notes.&lt;/p&gt;

&lt;p&gt;As an aside, a good readme should answer three essential questions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;What is this project?&lt;/strong&gt; A statement of intent and what the ultimate goal of the repository is trying to accomplish goes a long way.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;How do I get started?&lt;/strong&gt; This includes where to get the library, possibly building the source, or acessing the library through a package manager.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;What are some common use cases?&lt;/strong&gt; While you can’t account for all scenarios, there are likely common use cases your users will encounter. Spell them out. If there are known edge cases, spell those out too.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When adding the &lt;code&gt;Readme.md&lt;/code&gt; to your .NET repository, you’ll want to link it to each project that is packagable. &lt;a href=&quot;/a-dotnet-five-guide-from-idea-to-nuget-package&quot;&gt;Checkout out my NuGet guide here if you’re unfamiliar with setting up .NET projects for NuGet.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;updating-the-package-project&quot;&gt;Updating The Package Project&lt;/h2&gt;

&lt;p&gt;The way I accomplish this is by using the &lt;code&gt;Link&lt;/code&gt; functionality in a &lt;code&gt;csproj&lt;/code&gt; file. Let’s take a look at what that might look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;
    &amp;lt;None Remove=&quot;antiforgerySnippet.js&quot; /&amp;gt;
    &amp;lt;None Include=&quot;..\..\icon.png&quot; Pack=&quot;true&quot; PackagePath=&quot;&quot;&amp;gt;
        &amp;lt;Link&amp;gt;Properties\icon.png&amp;lt;/Link&amp;gt;
    &amp;lt;/None&amp;gt;
    &amp;lt;!-- IMPORTANT: adding the Readme as a link --&amp;gt;
    &amp;lt;None Include=&quot;..\..\README.md&quot; Pack=&quot;true&quot; PackagePath=&quot;&quot;&amp;gt;
        &amp;lt;Link&amp;gt;Properties\README.md&amp;lt;/Link&amp;gt;
    &amp;lt;/None&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The link can point to anywhere in your project, but I place most of my linked resources inside of the &lt;code&gt;Properties&lt;/code&gt; folder to keep the visual clutter to a minnimum. You’ll also need to have the &lt;code&gt;Pack&lt;/code&gt; attribute set to &lt;code&gt;true&lt;/code&gt; and the &lt;code&gt;PackagePath&lt;/code&gt; is set to the NuGet package root. I also have a package icon in this item group, which I also recommend adding.&lt;/p&gt;

&lt;p&gt;Next, you’ll need to add some additional elements to your project’s &lt;code&gt;PropertyGroup&lt;/code&gt; element, with the important tags for this tutorial being &lt;code&gt;PackageReadmeFile&lt;/code&gt;. I’ve included a complete &lt;code&gt;PropertyGroup&lt;/code&gt; section to see how it fits in with all the other &lt;code&gt;Package*&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PackageReadmeFile&lt;/code&gt; requires the path to the &lt;code&gt;Readme.md&lt;/code&gt; file within the NuGet package. Do not confuse this with where you place the file in your project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;PropertyGroup&amp;gt;
    &amp;lt;TargetFramework&amp;gt;netcoreapp3.1&amp;lt;/TargetFramework&amp;gt;
    &amp;lt;OutputType&amp;gt;Library&amp;lt;/OutputType&amp;gt;
    &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
    &amp;lt;LangVersion&amp;gt;Latest&amp;lt;/LangVersion&amp;gt;
    &amp;lt;IsPackable&amp;gt;true&amp;lt;/IsPackable&amp;gt;
    &amp;lt;PackageId&amp;gt;Htmx.TagHelpers&amp;lt;/PackageId&amp;gt;
    &amp;lt;Authors&amp;gt;Khalid Abuhakmeh&amp;lt;/Authors&amp;gt;
    &amp;lt;PackageIcon&amp;gt;icon.png&amp;lt;/PackageIcon&amp;gt;
    &amp;lt;RepositoryUrl&amp;gt;https://github.com/khalidabuhakmeh/Htmx.Net&amp;lt;/RepositoryUrl&amp;gt;
    &amp;lt;PackageLicenseExpression&amp;gt;MIT&amp;lt;/PackageLicenseExpression&amp;gt;
    &amp;lt;PackageTags&amp;gt;web,javascript&amp;lt;/PackageTags&amp;gt;
    &amp;lt;!-- IMPORTANT Do not forget this --&amp;gt;
    &amp;lt;PackageReadmeFile&amp;gt;README.md&amp;lt;/PackageReadmeFile&amp;gt;
    &amp;lt;Description&amp;gt;
        Adds ASP.NET Core tag helpers to make generating urls for Htmx (https://htmx.org) easier. Mimics the ASP.NET Core url tag helpers.
    &amp;lt;/Description&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’ve followed these steps correctly, then you should have a visible Readme on your NuGet packages home page. Congratulations! 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side Note:&lt;/strong&gt; NuGet.org will not respective relatively-linked resources such as images. If your file uses image references, be sure to have absolute paths to the images or else you’ll have an incomplete readme on NuGet.org.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you have it! With the use of a Readme file, a &lt;code&gt;Link&lt;/code&gt; element, and &lt;code&gt;PackageReadmeFile&lt;/code&gt; element you too can have a better looking NuGet package page. It can give you and your package a greater chance of being picked and it can help grow your little corner of the .NET community.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 04 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/adding-a-readme-to-nuget-package-landing-pages</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/adding-a-readme-to-nuget-package-landing-pages</guid>
        
        <category>dotnet</category>
        
        <category>nuget</category>
        
        
      </item>
    
      <item>
        <title>HTMX Boosts and ASP.NET Core Anti-Forgery Tokens</title>
        <description>&lt;p&gt;I maintain an ASP.NET Core enhancement library focused on integrating &lt;a href=&quot;https://htmx.org&quot;&gt;HTMX&lt;/a&gt; naturally into your web development workflow. It works great, but I must admit that HTMX is doing much of the heavy lifting regarding developer experience; it’s incredible! That said, &lt;a href=&quot;https://github.com/khalidabuhakmeh/htmx.net&quot;&gt;my library (HTMX.NET)&lt;/a&gt; helps smooth out some of the edges that come with integrating the two parts of the experience: ASP.NET Core and the HTML UI.&lt;/p&gt;

&lt;p&gt;In this post, I’ll discuss how to work with anti-forgery tokens and some techniques I’ve taken to help mitigate the issues you might run into when working with HTMX boosts and ASP.NET Core security measures.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-htmx-and-whats-a-boost&quot;&gt;What is HTMX and What’s a Boost?&lt;/h2&gt;

&lt;p&gt;HTMX is a client-side library that takes a hypermedia approach to manage user interaction between the client and the server. In simpler terms, HTMX works with HTML fragments and replaces DOM elements based on an HTML server response. While seemingly simple, this approach is robust and used by organizations like GitHub and the Ruby on Rails community.&lt;/p&gt;

&lt;p&gt;HTMX also supports the concept of &lt;strong&gt;Boost&lt;/strong&gt;. In practice, boosting requires no changes to the server-side implementation but can increase perceived user performance on the client. HTMX can intercept any anchor-based web request and then process the response, replacing the page’s existing &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element with the response’s version. Boosting can limit client-side parsing to the elements in the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag while eliminating the need for requesting and reprocessing the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element and all its resources, such as scripts and cascading stylesheets.&lt;/p&gt;

&lt;p&gt;While boosting has benefits, there are drawbacks you should be aware of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Any changes in the head are not automatically processed, except for the page’s title.&lt;/li&gt;
  &lt;li&gt;Additional scripts in the body will be reprocessed, leading to rerunning scripts (and potential re-registration of event handlers).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following the previous best practices of placing scripts just before the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag ends, these drawbacks become apparent. Also, when working with ASP.NET Core anti-forgery tokens, as currently, the HTMX.NET library adds a global token to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag to be used generally by &lt;strong&gt;POST&lt;/strong&gt; requests. Finally, for your information, it’s best practice to use &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; elements, as ASP.NET Core gives forms a new anti-forgery token to use on submissions.&lt;/p&gt;

&lt;p&gt;The goal is to update anti-forgery tokens and stop event handlers from being re-registered. So how did I accomplish that?&lt;/p&gt;

&lt;h2 id=&quot;scripts-within-the-body-tag&quot;&gt;Scripts Within The Body Tag&lt;/h2&gt;

&lt;p&gt;Since HTMX boosts only replace the contents of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, not the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag itself, I can add additional metadata to the DOM element that survives while the page session is still active. For example, if the script executes at the end of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, we can wrap all scripts with the following check.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;if (!document.body.attributes.__htmx_antiforgery) {
    // register HTMX event handlers here
    document.body.attributes.__htmx_antiforgery = true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That solves the multiple registrations of event handlers issue, and now we can handle boosts. In the latest release of HTMX (1.9.2), we have more metadata to determine if a response resulted from a boosted request. So after a response is loaded but yet to be processed, we can glean the latest anti-forgery token from the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element of the response.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;document.addEventListener(&quot;htmx:afterOnLoad&quot;, evt =&amp;gt; {
    if (evt.detail.boosted) {
        const parser = new DOMParser();
        const html = parser.parseFromString(evt.detail.xhr.responseText, &apos;text/html&apos;);
        const selector = &apos;meta[name=htmx-config]&apos;;
        const config = html.querySelector(selector);
        if (config) {
            const current = document.querySelector(selector);
            // only change the anti-forgery token
            const key = &apos;antiForgery&apos;;
            htmx.config[key] = JSON.parse(config.attributes[&apos;content&apos;].value)[key];
            // update DOM, probably not necessary, but for sanity&apos;s sake
            current.replaceWith(config);
        }
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This JavaScript event handler will keep our anti-forgery tokens up to date on each full-page boost. Neat!&lt;/p&gt;

&lt;p&gt;While this approach works in the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, I think there’s a better way.&lt;/p&gt;

&lt;h2 id=&quot;add-script-to-head-and-defer&quot;&gt;Add Script to Head and Defer&lt;/h2&gt;

&lt;p&gt;The JavaScript I’ve written for HTMX.NET works excellently, but we can use the registration differently to avoid some of the abovementioned issues.&lt;/p&gt;

&lt;p&gt;By changing how the client can access the script, we can take advantage of some newer concepts in resource management. The first step is to register an endpoint that can serve our initial script.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace Htmx.TagHelpers;

public static class HtmxAntiforgeryScriptEndpoints
{
    /// &amp;lt;summary&amp;gt;
    /// The path to the anti-forgery script that is used from HTML
    /// &amp;lt;/summary&amp;gt;
    public static string Path { get; private set; } = &quot;_htmx/antiforgery.js&quot;;
    
    /// &amp;lt;summary&amp;gt;
    /// Register an endpoint that responds with the HTMX anti-forgery script.&amp;lt;br/&amp;gt;
    /// IMPORTANT: Remember to add the following script tag to your _Layout.cshtml or Razor view:
    /// &amp;lt;![CDATA[
    /// &amp;lt;script src=&quot;@HtmxAntiforgeryScriptEndpoints.Path&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
    /// ]]&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&quot;builder&quot;&amp;gt;Endpoint builder&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&quot;path&quot;&amp;gt;The path to the anti-forgery script&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;The registered endpoint (Use &amp;lt;seealso cref=&quot;Path&quot;/&amp;gt; to reference endpoint)&amp;lt;/returns&amp;gt;
    public static IEndpointConventionBuilder MapHtmxAntiforgeryScript(
        this IEndpointRouteBuilder builder,
        string? path = null)
    {
        // set Path globally for access
        Path = path ?? Path;
        
        return builder.MapGet(Path, async ctx =&amp;gt;
        {
            ctx.Response.ContentType = &quot;text/javascript&quot;;
            await ctx.Response.WriteAsync(HtmxSnippets.AntiforgeryJavaScript);
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can register our endpoint with our ASP.NET Core application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapHtmxAntiforgeryScript();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The added benefit here is we can now add response caching and other endpoint filters to alter how this script is delivered.&lt;/p&gt;

&lt;p&gt;Finally, with the keyword’ defer’, we can add the script to our &lt;code&gt;_Layout.cshtml&lt;/code&gt; file in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;/&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&amp;gt;
    &amp;lt;meta
        name=&quot;htmx-config&quot;
        historyCacheSize=&quot;20&quot;
        indicatorClass=&quot;htmx-indicator&quot;
        includeAspNetAntiforgeryToken=&quot;true&quot;/&amp;gt;
    &amp;lt;title&amp;gt;@ViewData[&quot;Title&quot;] - Htmx.Sample&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/lib/bootstrap/dist/css/bootstrap.min.css&quot;/&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/css/site.css&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    &amp;lt;script src=&quot;~/lib/jquery/dist/jquery.min.js&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;~/lib/bootstrap/dist/js/bootstrap.bundle.min.js&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;https://unpkg.com/htmx.org@@1.9.2&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;@HtmxAntiforgeryScriptEndpoints.Path&quot; defer&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; keyword will download the script parallel to parsing the page and only execute it after the client has finished parsing. The keyword keeps our scripts from blocking the critical rendering path.&lt;/p&gt;

&lt;p&gt;While our script contains the &lt;code&gt;if&lt;/code&gt; block, it is unnecessary now since HTMX boosts will not reload any of the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; elements. Neat!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;HTMX has many great features out-of-the-box, but it’s still necessary to fuse the elements of HTMX to your technology stack of choice. In my case, and likely yours, that’s ASP.NET Core. So you should expect this update in the current feature set of HTMX.NET. If you use HTMX.NET, please let me know what you think and where I can improve it.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts. Cheers :)&lt;/p&gt;
</description>
        <pubDate>Tue, 27 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/htmx-boosts-and-aspnet-core-anti-forgery-tokens</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/htmx-boosts-and-aspnet-core-anti-forgery-tokens</guid>
        
        <category>htmx,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Using StringBuilder To Replace Values</title>
        <description>&lt;p&gt;Have you ever had to clean up your users’ input, only to realize the pain and aggravation it can lead to with all the unnecessary memory overhead? I recently had an “aha!” moment and thought I would share this tip with you.&lt;/p&gt;

&lt;p&gt;This article will be short, but I’ll try to give you some context as we go along. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;calculators-and-user-input&quot;&gt;Calculators and User Input&lt;/h2&gt;

&lt;p&gt;I recently looked at a sample calculator project from &lt;a href=&quot;https://github.com/naweed&quot;&gt;MAUI developer Naweed Akram&lt;/a&gt;. He has some fantastic MAUI samples, and his &lt;a href=&quot;https://github.com/naweed/MauiScientificCalculator&quot;&gt;Scientific Calculator&lt;/a&gt; is impressive. Check it out, seriously. He uses the &lt;a href=&quot;https://github.com/ncalc/ncalc&quot;&gt;NCalc&lt;/a&gt; library to parse &lt;code&gt;string&lt;/code&gt; expressions and evaluate the result. It’s a very cool library but has a caveat. Functions are case-sensitive, so user input must be constrained or normalized. Naweed chose the normalization path, and his implementation is similar to the approach I would have taken myself. Let’s take a look at it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private string NormalizeInputString()
{
    Dictionary&amp;lt;string, string&amp;gt; _opMapper = new()
    {
        {&quot;×&quot;, &quot;*&quot;},
        {&quot;÷&quot;, &quot;/&quot;},
        {&quot;SIN&quot;, &quot;Sin&quot;},
        {&quot;COS&quot;, &quot;Cos&quot;},
        {&quot;TAN&quot;, &quot;Tan&quot;},
        {&quot;ASIN&quot;, &quot;Asin&quot;},
        {&quot;ACOS&quot;, &quot;Acos&quot;},
        {&quot;ATAN&quot;, &quot;Atan&quot;},
        {&quot;LOG&quot;, &quot;Log&quot;},
        {&quot;EXP&quot;, &quot;Exp&quot;},
        {&quot;LOG10&quot;, &quot;Log10&quot;},
        {&quot;POW&quot;, &quot;Pow&quot;},
        {&quot;SQRT&quot;, &quot;Sqrt&quot;},
        {&quot;ABS&quot;, &quot;Abs&quot;},
    };
    
    var retString = InputText;
    foreach (var key in _opMapper.Keys)
    {
        retString = retString.Replace(key, _opMapper[key]);
    }

    return retString;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The method uses a &lt;code&gt;Dictionary&lt;/code&gt; of keys and values to force specific casing to match what NCalc expects from the user. While functional, there is room to optimize performance.&lt;/p&gt;

&lt;p&gt;In the previous code, the method call to &lt;code&gt;Replace&lt;/code&gt; creates a new string in memory for each replacement. So, in a worst-case scenario, we could have 15 new strings allocated as we clean the user’s equation, one for each key and the original value. Yikes!&lt;/p&gt;

&lt;p&gt;What should we do?!&lt;/p&gt;

&lt;h2 id=&quot;using-stringbuilder-to-replace&quot;&gt;Using StringBuilder To Replace&lt;/h2&gt;

&lt;p&gt;We commonly think of &lt;code&gt;StringBuilder&lt;/code&gt; as a class to build up new string values, but it didn’t occur to me that &lt;code&gt;StringBuilder&lt;/code&gt; could also be used to alter an existing string efficiently. So, let’s update the code sample.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private string NormalizeInputString()
{
    Dictionary&amp;lt;string, string&amp;gt; _opMapper = new()
    {
        {&quot;×&quot;, &quot;*&quot;},
        {&quot;÷&quot;, &quot;/&quot;},
        {&quot;SIN&quot;, &quot;Sin&quot;},
        {&quot;COS&quot;, &quot;Cos&quot;},
        {&quot;TAN&quot;, &quot;Tan&quot;},
        {&quot;ASIN&quot;, &quot;Asin&quot;},
        {&quot;ACOS&quot;, &quot;Acos&quot;},
        {&quot;ATAN&quot;, &quot;Atan&quot;},
        {&quot;LOG&quot;, &quot;Log&quot;},
        {&quot;EXP&quot;, &quot;Exp&quot;},
        {&quot;LOG10&quot;, &quot;Log10&quot;},
        {&quot;POW&quot;, &quot;Pow&quot;},
        {&quot;SQRT&quot;, &quot;Sqrt&quot;},
        {&quot;ABS&quot;, &quot;Abs&quot;},
    };
    
    var retString = new StringBuilder(InputText);
    foreach (var key in _opMapper.Keys)
    {
        retString.Replace(key, _opMapper[key]);
    }

    return retString.ToString();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we only generate two strings: the original input and the final result. You might be asking, “how much of a difference can this make, really?”. Well, every optimization is contextual and will depend on your use case. But, we can reduce some unnecessary memory pressure for a relatively simple change.&lt;/p&gt;

&lt;p&gt;Let’s use Benchmarkdotnet to compare the previous implementation and the &lt;code&gt;StringBuilder&lt;/code&gt; approach.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run&amp;lt;StringReplace&amp;gt;();

[MemoryDiagnoser]
[ShortRunJob]
public class StringReplace
{
    readonly Dictionary&amp;lt;string, string&amp;gt; map = new()
    {
        { &quot;×&quot;, &quot;*&quot; },
        { &quot;÷&quot;, &quot;/&quot; },
        { &quot;SIN&quot;, &quot;Sin&quot; },
        { &quot;COS&quot;, &quot;Cos&quot; },
        { &quot;TAN&quot;, &quot;Tan&quot; },
        { &quot;ASIN&quot;, &quot;Asin&quot; },
        { &quot;ACOS&quot;, &quot;Acos&quot; },
        { &quot;ATAN&quot;, &quot;Atan&quot; },
        { &quot;LOG&quot;, &quot;Log&quot; },
        { &quot;EXP&quot;, &quot;Exp&quot; },
        { &quot;LOG10&quot;, &quot;Log10&quot; },
        { &quot;POW&quot;, &quot;Pow&quot; },
        { &quot;SQRT&quot;, &quot;Sqrt&quot; },
        { &quot;ABS&quot;, &quot;Abs&quot; },
    };

    private const string target = &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot; +
                                  &quot;1 x 1 ÷ 1 * SIN(COS(TAN(LOG(ASIN(ATAN(EXP(POW(SQRT(ABS(1))))))))))  |&quot;;

    [Benchmark]
    public string String()
    {
        var result = target;
        foreach (var key in map.Keys)
        {
            result = result.Replace(key, map[key]);
        }

        return result;
    }

    [Benchmark]
    public string StringBuilder()
    {
        var result = new StringBuilder(target);
        foreach (var key in map.Keys)
        {
            result.Replace(key, map[key]);
        }

        return result.ToString();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s see the results of the Benchmarkdotnet run.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;|        Method |     Mean |    Error |    StdDev |   Gen0 | Allocated |
|-------------- |---------:|---------:|----------:|-------:|----------:|
|        String | 3.967 us | 1.673 us | 0.0917 us | 1.8082 |  11.11 KB |
| StringBuilder | 3.480 us | 2.472 us | 0.1355 us | 0.4082 |   2.52 KB |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow! The &lt;code&gt;StringBuilder&lt;/code&gt; implementation allocates about 20% of what the &lt;code&gt;String&lt;/code&gt; implementation does. That’s a pretty significant performance optimization for code that looks almost identical. These increases can become more effective as the target string grows or the dictionary of keys/values expands.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While you may think of &lt;code&gt;StringBuilder&lt;/code&gt; as a means to build strings over several iterations, you can also think of &lt;code&gt;StringBuilder&lt;/code&gt; as an alteration tool. Utilizing the &lt;code&gt;Replace&lt;/code&gt; method could reduce memory overhead while keeping the code almost the same. Given the benchmark comparison, you can also see reduced Gen0 sizes, which should minimize garbage collection pauses over time. It’s a win-win.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this blog post, and please feel free to share it with colleagues and friends. As always, thanks for reading.&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/using-stringbuilder-to-replace-values</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/using-stringbuilder-to-replace-values</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>The Privilege of .NET Tooling Choices</title>
        <description>&lt;p&gt;Regarding the .NET ecosystem, we’ve become spoiled with great tooling choices from Visual Studio, JetBrains Rider, VS Code, and NeoVIM, not to mention the extension ecosystem like ReSharper, CodeRush, and OzCode. As a result, the ability to define your development workflow and your team’s workflow has never been more varied. What a time to be a .NET developer!&lt;/p&gt;

&lt;p&gt;With choice comes the burden of improving your productivity while not hampering the preferences of your team members. After all, all of us have years of different experiences and skill sets that no single tool can satisfy.
A development tool that tries to please everyone is doomed to please no one.&lt;/p&gt;

&lt;p&gt;So I wanted to use this time to describe my philosophy when picking development tools and why I think it’s vital for personal and team happiness and completing development projects.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;picking-personal-tools&quot;&gt;Picking Personal Tools&lt;/h2&gt;

&lt;p&gt;When it comes to defining my development environment, I believe it is a deeply personal choice. I prefer the operating system I like (macOS) and IDE I work with (JetBrains Rider). Over 15 years, I’ve found the combination of tooling that works for me, but I’m also willing to consider other options as the technology landscape changes. I also understand my personal choices will not be another individual’s. So instead of arguing about personal preferences, finding ways to be a better development neighbor is more important.&lt;/p&gt;

&lt;p&gt;In the pursuit of being a good development partner, I have a  &lt;strong&gt;“must follow”&lt;/strong&gt; rule:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;My tooling choices should not burden other developers with my preferences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, if I choose a tool, it must abide by at least one of two criteria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The tool is transparent to other team members. It doesn’t pollute the shared spaces with my preference and put my team members at the disadvantage of dealing with my “junk”.&lt;/li&gt;
  &lt;li&gt;If my tool produces artifacts, other team members must be able to utilize those artifacts regardless of all of our preferences. (we’ll talk more about this later).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does “polluting” constitute? If a codebase is a communal shared space by team members, my tools shouldn’t leave artifacts that team members didn’t agree to use. These artifacts include tool-specific configuration files, assets, or dependencies. These artifacts are one more burden a team must manage, which would constitute selfish behavior on my part.&lt;/p&gt;

&lt;p&gt;In my attempt to stay on the good side of karma, a tool needs to provide at least two options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Assets are optional; tooling can work with or without the extra configuration.&lt;/li&gt;
  &lt;li&gt;Assets can exist locally in my development environment without me checking the files in source control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These characteristics allow me to make my choice and still be a good team member. Everyone wins.&lt;/p&gt;

&lt;h2 id=&quot;picking-team-tools&quot;&gt;Picking Team Tools&lt;/h2&gt;

&lt;p&gt;Given the promise of .NET being a cross-platform technology stack, the shared tools a team picks should reflect that value. So, for example, tools might include test runners, HTTP clients, static analysis tooling, and build pipeline enhancements. This brings me to my subsequent &lt;strong&gt;“must follow”&lt;/strong&gt; rule:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any tool a team adopts must account for running locally on any developer’s preferred environment and provide value to all team members.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what do I look for in team tooling choices?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A tool must provide value to a majority of team members. Therefore, a consensus on what constitutes value is essential to adopting tools. Adding dependencies is a burden, after all.&lt;/li&gt;
  &lt;li&gt;A team tool must be cross-platform. A Windows or Unix-only tool doesn’t benefit everyone and should be crossed off the list immediately. It’s time we expect better from our team tools.&lt;/li&gt;
  &lt;li&gt;Any tool that processes files should provide a CLI version of itself. A CLI tool allows team members to get value from shared assets even if they might not have a comparable experience an IDE plugin might provide. A CLI tool also means you can get similar results in CI/CD pipelines and locally. At the very least, the tool should be accessible to everyone via a web interface if it is a subscription service-style tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a team setting, a team tool should not penalize my macOS choice, favoring a team member’s Windows experience, and vice versa. Likewise, a team member’s use of a Visual Studio extension should not hamper my JetBrains Rider experience. And ultimately, a tool that I can run in a CI/CD environment must also run locally. Adopting a tool that favors one group over another creates unnecessary friction and fragmentation. That friction leads to resentment and conflict, lowering team productivity.&lt;/p&gt;

&lt;p&gt;Team-focused tools should also be accessible to all team members in the same capacity, as everyone should be able to manage and maintain them. After all, the team agreed on the value of adopting the tool, right? With the complexity of the modern software development lifecycle, teams should limit their risk exposure. A team tool that only works in specific circumstances and is only accessible to certain team members is a liability.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As .NET developers, we have a glut of choices in front of us, and while we each have our particular favorites, we also need to understand the team-based nature of software development. When we take those choices away from team members, we create an environment devoid of diversity and creativity, which I try to avoid as much as possible. The .NET ecosystem and the folks working in it should champion team productivity and create a base experience everyone can rely on, regardless of anyone’s personal tooling choices. I hope you leave being mindful of how individual choices can affect a team’s productivity and, ultimately, the vibrancy of the .NET ecosystem.&lt;/p&gt;

</description>
        <pubDate>Tue, 13 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/the-privilege-of-dotnet-tooling-choices</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/the-privilege-of-dotnet-tooling-choices</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Entity Framework Core 7: Filtering on JSON Arrays</title>
        <description>&lt;p&gt;Entity Framework Core 7 introduced developers to JSON column support. &lt;a href=&quot;https://blog.jetbrains.com/dotnet/2023/02/14/getting-started-entity-framework-core-7-json-support&quot;&gt;I even wrote about it on the JetBrains .NET blog&lt;/a&gt;, and it has been generally well-received. However, recently a user tried my sample project, only to find that they could not filter on a collection of JSON values. Given the current Microsoft SQL Server provider, the following LINQ statement does not work.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var results = await db.Posts
    .Where(x =&amp;gt; x.Tags.Any(t =&amp;gt; t.Value == &quot;CSharp&quot;))
    .ToListAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Entity Framework Core will throw the following exception.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;The LINQ expression &apos;DbSet&amp;lt;Post&amp;gt;()
    .Where(p =&amp;gt; EF.Property&amp;lt;List&amp;lt;Tag&amp;gt;&amp;gt;(p, &quot;Tags&quot;)
        .AsQueryable()
        .Any(o =&amp;gt; o.Value == &quot;CSharp&quot;))&apos; 
could not be translated.
Either rewrite the query in a form that can be translated, 
or switch to client evaluation explicitly by inserting a 
call to &apos;AsEnumerable&apos;, &apos;AsAsyncEnumerable&apos;, &apos;ToList&apos;, 
or &apos;ToListAsync&apos;. See https://go.microsoft.com/fwlink/?linkid=2101038 
for more information.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re experiencing this issue and need to filter on a JSON array, I have several SQL queries to help you work around this issue. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;sql-to-the-rescue&quot;&gt;SQL to the Rescue&lt;/h2&gt;

&lt;p&gt;Luckily, in later versions of Entity Framework, we have access to the &lt;code&gt;FromSql&lt;/code&gt; methods that can allow us to seed the &lt;code&gt;From&lt;/code&gt; clause with a sub-query. The advantage of this approach is we can still use many of the features of LINQ from a starting result set. But before we get to the C# code, let’s look at some queries against our data model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var blogPost = new Post
{
    Title = &quot;Writing about .NET&quot;,
    Author =
    {
        Name = &quot;Khalid Abuhakmeh&quot;,
        ImageUrl = &quot;/khalidabuhakmeh.jpg&quot;,
        SocialMediaUrl = &quot;@khalidabuhakmeh@mastodon.social&quot;
    },
    Tags =
    {
        new Tag { Value = &quot;dotnet&quot; },
        new Tag { Value = &quot;drop&quot; }, 
        new Tag { Value = &quot;dot&quot; }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Tags&lt;/code&gt; are stored as a JSON Column in the following form.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;[{&quot;Value&quot;:&quot;dotnet&quot;},{&quot;Value&quot;:&quot;drop&quot;},{&quot;Value&quot;:&quot;dot&quot;}]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So how do you filter a row based on whether a tag exists in your collection of tag values? Well, there are a few ways. I’ve included them below with the &lt;strong&gt;Total Cost&lt;/strong&gt; according to running them on a dataset of 500 rows. Of course, a lower value is better, but check it against your dataset and consult your local DBA.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Total Cost: 0.00527086
SELECT *
FROM Posts p
CROSS APPLY OPENJSON(p.Tags)
WITH (Tag VARCHAR(300) &apos;$.Value&apos;) as Tag
Where Tag = &apos;dotnet&apos;

-- Total Cost: 0.0651177
SELECT *
From Posts posts
WHERE (SELECT Tag as tag
       FROM OPENJSON(Tags) WITH (Tag VARCHAR(300) &apos;$.Value&apos;) AS Tag
       WHERE Tag = &apos;dotnet&apos;) = &apos;dotnet&apos;

-- Total Cost: 0.0304298
SELECT *
From Posts posts
WHERE EXISTS 
  (SELECT Tag as tag
   FROM OPENJSON(Tags) WITH (Tag VARCHAR(300) &apos;$.Value&apos;) AS Tag
   WHERE Tag = &apos;dotnet&apos;)

-- Total Cost: 0.0297937
SELECT *
From Posts posts
WHERE EXISTS 
 (SELECT Value
  FROM OPENJSON(Tags) WITH (Value VARCHAR(300) &apos;$.Value&apos;) AS Value
  WHERE Value in (&apos;dotnet&apos;, &apos;drop&apos;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ve included variants that support multiple tag filtering or several values. Use the one for your use case.&lt;/p&gt;

&lt;p&gt;Now that we have a SQL query, how do we use it in Entity Framework Core?&lt;/p&gt;

&lt;p&gt;Well, I had mentioned the use of &lt;code&gt;FromSql&lt;/code&gt;, and we can do just that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var values = new object[] { &quot;drop&quot;, &quot;dot&quot; };
var placeholders = string.Join(&quot;,&quot;, values.Select((_, i) =&amp;gt; $&quot;{{{i}}}&quot;).ToArray());

var list = await db.Posts.FromSqlRaw(
        $&quot;SELECT * From Posts posts WHERE EXISTS (SELECT Value FROM OPENJSON(Tags) WITH (Value VARCHAR(300) &apos;$.Value&apos;) AS Value WHERE Value in ({placeholders}))&quot;, values)
    .ToListAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I decided to use the &lt;code&gt;Exists&lt;/code&gt; versions of my SQL queries, as they are the most straightforward to reason about, and it supports multiple tags. I also needed to parameterize the user input, which should keep the query safe against SQL injection attacks.&lt;/p&gt;

&lt;p&gt;You can add additional filters to the base query, like the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var list = await db.Posts.FromSqlRaw(&quot;&amp;lt;SQL&amp;gt;&quot;)
    .Where(p =&amp;gt; p.Id == 2)
    .ToListAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The generated SQL query will appear in the console’s output.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;info: 5/8/2023 14:21:20.802 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) 
      Executed DbCommand (91ms) [Parameters=[p0=&apos;drop&apos; (Size = 4000), p1=&apos;dot&apos; (Size = 4000)], CommandType=&apos;Text&apos;, CommandTimeout=&apos;30&apos;]
      SELECT [c].[Id], [c].[CreateAt], [c].[Permalink], [c].[Title], [c].[UpdatedAt], JSON_QUERY([c].[Author],&apos;$&apos;), JSON_QUERY([c].[Tags],&apos;$&apos;)
      FROM (
          SELECT * From Posts posts WHERE EXISTS (SELECT Value FROM OPENJSON(Tags) WITH (Value VARCHAR(300) &apos;$.Value&apos;) AS Value WHERE Value in (@p0,@p1))
      ) AS [c]
      WHERE [c].[Id] = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome! Well, I have one more option for you, but I do think it’s the inferior option. That said, for the sake of completeness, here it is.&lt;/p&gt;

&lt;h2 id=&quot;using-likes-to-filter-rows&quot;&gt;Using Likes To Filter Rows&lt;/h2&gt;

&lt;p&gt;The solution presented above will use the JSON features of Microsoft SQL Server to accurately filter rows based on the values in a JSON object. If you’re dealing with simpler data, as I am in this post, a &lt;code&gt;LIKE&lt;/code&gt; query might be good enough.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var value = &quot;%\&quot;dotnet\&quot;%&quot;;
var one = await db.Posts
     .FromSqlRaw(&quot;SELECT * FROM Posts WHERE Tags LIKE {0}&quot;, value)
     .FirstOrDefaultAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This approach certainly works, but has the disadvantage of using double-sided wildcards, which is known for being less-than optimal when it comes to performance. You also have to deal with creating the filter value with the use of &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;&quot;&lt;/code&gt; characters.&lt;/p&gt;

&lt;p&gt;It’s an option if you need it, but I really do recommend the previous approach.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While Entity Framework Core introduced JSON support, &lt;a href=&quot;https://blog.jetbrains.com/dotnet/2023/02/14/getting-started-entity-framework-core-7-json-support&quot;&gt;as I wrote about in my JetBrains blog post&lt;/a&gt;, it sadly is missing collection filtering. However, using the &lt;code&gt;FromSql&lt;/code&gt; variant methods, you can get it working while retaining the strengths of LINQ and query filtering. In addition, you can take the extra step to add much of the functionality mentioned here into an extension method. The one drawback to using &lt;code&gt;FromSql&lt;/code&gt; is that it becomes the foundation for all future filtering, which may make it challenging to optimize your LINQ queries without adding more to the original SQL statement. In conclusion, I’m pretty happy with this approach, but looking forward to the day that Entity Framework Core supports this functionality out of the box.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and thank you for reading and sharing my content with others.&lt;/p&gt;

</description>
        <pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/entity-framework-core-7-filtering-on-json-arrays</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/entity-framework-core-7-filtering-on-json-arrays</guid>
        
        <category>dotnet,</category>
        
        <category>entity-framework</category>
        
        
      </item>
    
      <item>
        <title>JavaScript Import Maps For ASP.NET Core Developers</title>
        <description>&lt;p&gt;If you’re building web applications, you’ll likely have to write some JavaScript, so why not write the best JavaScript you can? The JavaScript ecosystem has evolved with an emphasis on performance and user experience, and if you’ve avoided writing JavaScript for a while now, you’ll be pleasantly surprised.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://web.dev/import-maps-in-all-modern-browsers/&quot;&gt;Import Maps is the latest advancement&lt;/a&gt;, a technique to make managing and consuming EcmaScript modules (ESM) much more straightforward for client-side developers. Ultimately, it brings the same style of development Node developers have enjoyed on the server side of the ecosystem to the browser.&lt;/p&gt;

&lt;p&gt;In this post, we’ll compare traditional script referencing to ESM, how to write a simple ESM file, how to use it in your Razor-powered ASP.NET Core applications, and some good-to-know facts.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;What is ESM and Why Should I Care?&lt;/p&gt;

&lt;p&gt;JavaScript implementations have transitioned from unstructured code living in a global context to codebases depending on easy-to-follow structures. Let’s look at a simple module and how you can consume it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// file name: simple.js
export default function () {
    console.log(&apos;hello world!&apos;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s use our module that exports a function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import Simple from &quot;./simple.js&quot;;
Simple();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that authoring and consuming a module has intention behind it. You can tell where a module is coming from and what parts of the module you use. There’s no surprise global variables or opportunities for unresolvable conflicts. So why is this better?&lt;/p&gt;

&lt;p&gt;If you’ve spent any time doing web development, you’re likely familiar with JQuery and how it’s referenced and used in a web application. The breakdown is not to pick on JQuery but to demonstrate some issues with traditionally-written libraries.&lt;/p&gt;

&lt;p&gt;The foremost trait of a traditional script is that you reference it on a web page like so.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;/libs/jquery/3.6.4/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While perfectly fine, there are a few drawbacks to referencing scripts this way.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Scripts are blocking and will stop the page from processing until all content is loaded.&lt;/li&gt;
  &lt;li&gt;Script variables and functions are global and may conflict with other scripts.&lt;/li&gt;
  &lt;li&gt;Selectively loading dependencies requires server-side templating to toggle elements or client-side code that dynamically injects script tags.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In our ESM example, you can reference scripts using the &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;module&lt;/code&gt; in your Razor pages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&quot;~/js/site.js&quot; type=&quot;module&quot; asp-append-version=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The presence of &lt;code&gt;type=module&lt;/code&gt; tells the browser to load the file with the knowledge that it is using ESM and to respect &lt;code&gt;import&lt;/code&gt; statements. Only dependencies that are part of the import graph will be loaded, and additionally, all modules are deferred by default, meaning they won’t block the page rendering.&lt;/p&gt;

&lt;p&gt;So how do import maps factor into all of this?&lt;/p&gt;

&lt;h2 id=&quot;import-maps-and-why-theyre-important&quot;&gt;Import Maps and Why They’re Important&lt;/h2&gt;

&lt;p&gt;Import maps allow you to define aliases for internal and external dependencies used in your JavaScript. For example, look at the import map from my sample ASP.NET Core Razor Pages project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&quot;importmap&quot;&amp;gt;
{
    &quot;imports&quot; : {
        &quot;vue&quot;: &quot;https://unpkg.com/vue@3/dist/vue.esm-browser.js&quot;,
        &quot;hello-world&quot;: &quot;@Url.Content(&quot;~/js/hello-world.js&quot;)&quot;,
        &quot;simple&quot;: &quot;@Url.Content(&quot;~/js/simple.js&quot;)&quot;
    }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you’ve defined an import map, you can use the aliases anywhere in your client-side environment. For example, here is the implementation for &lt;code&gt;hello-world.js&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { createApp } from &quot;vue&quot;;

export default function helloWorld(target, message) {
    createApp({
        data() {
            return {
                message: message
            }
        }
    }).mount(target)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that I’m importing the &lt;code&gt;vue&lt;/code&gt; dependency, which points to an ESM version of the Vue library. &lt;strong&gt;It’s important that any library imported also be written in the ESM style.&lt;/strong&gt; All without immediately knowing what &lt;code&gt;vue&lt;/code&gt; is used during my usage. The flexibility allows for more centralized dependencies updates without affecting large swaths of my codebase.&lt;/p&gt;

&lt;p&gt;We can also import a module within our HTML pages using a’ script’ tag element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;script type=&quot;module&quot;&amp;gt;
import helloWorld from &apos;hello-world&apos;;
helloWorld(&apos;#app&apos;, &apos;Hello From ASP.NET Core&apos;);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome right?!&lt;/p&gt;

&lt;p&gt;Now our ASP.NET Core pages can selectively use dependencies from our JavaScript modules, with the added benefit of only loading the libraries we need. What a fantastic feature.&lt;/p&gt;

&lt;p&gt;You might be thinking, how can ASP.NET Core do more in this situation? How about importing JSON files into your clientside apps? That would be cool, right? Well, you can!&lt;/p&gt;

&lt;p&gt;Let’s first define a JSON endpoint using Minimal APIs.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;app.MapGet(&quot;/config&quot;, 
    () =&amp;gt; new { name = &quot;Khalid&quot; });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we’ll modify our import map to point to this new endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&quot;importmap&quot;&amp;gt;
{
    &quot;imports&quot; : {
        &quot;vue&quot;: &quot;https://unpkg.com/vue@3/dist/vue.esm-browser.js&quot;,
        &quot;hello-world&quot;: &quot;@Url.Content(&quot;~/js/hello-world.js&quot;)&quot;,
        &quot;simple&quot;: &quot;@Url.Content(&quot;~/js/simple.js&quot;)&quot;,
        &quot;config&quot;: &quot;@Url.Content(&quot;~/config&quot;)&quot;
    }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, we can import and use our JSON response in our client-side script. You must assert that the module import is of type &lt;code&gt;json&lt;/code&gt; for it to work correctly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;
import config from &apos;config&apos; assert { type: &apos;json&apos; };
import helloWorld from &apos;hello-world&apos;;
helloWorld(&apos;#app&apos;, `Hello ${config.name} From ASP.NET Core`);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that there might still be compatibility issues with &lt;code&gt;assert&lt;/code&gt; statements across browser vendors. Please consult the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&quot;&gt;Mozilla documentation to see if your browser supports particular features with modules&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;general-thoughts-on-import-maps&quot;&gt;General Thoughts on Import Maps&lt;/h2&gt;

&lt;p&gt;I have some thoughts I’d love to share with you about some advantages of this approach.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Modules and import statements are very natural for C# developers, so the move to this style of development should be easier for most folks.&lt;/li&gt;
  &lt;li&gt;The deferment of these scripts by default means you get an added performance boost to your user experience. Who doesn’t want that?!&lt;/li&gt;
  &lt;li&gt;The combination of JavaScript code using ASP.NET Core server-rendered content is powerful.&lt;/li&gt;
  &lt;li&gt;Import maps make it easy to manage dependencies, regardless if you’re using a build tool or want to use prebuilt dependencies. It’s great!&lt;/li&gt;
  &lt;li&gt;All your dependencies must be ESM compatible, so trying to import commonJS files will not work.&lt;/li&gt;
  &lt;li&gt;Don’t forget to add &lt;code&gt;type=module&lt;/code&gt; to your script tags. It’s easy to forget and can leave you scratching your head.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://web.dev/import-maps-in-all-modern-browsers/&quot;&gt;All major browsers now support import maps&lt;/a&gt;, and ESM is the future of writing JavaScript. It’s also a great way to update your existing clientside development workflow without taking on large build toolchains. You’ll need to seek out ESM-compatible libraries, but many of the most popular ones have already started the shift. In combination with ASP.NET Core, you can use the dynamic server-side generation tools to interact and enhance your client-side experience. It’s a win-win for everyone.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and as always, thanks for reading and sharing my content.&lt;/p&gt;
</description>
        <pubDate>Tue, 30 May 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/javascript-import-maps-for-aspnet-core-developers</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/javascript-import-maps-for-aspnet-core-developers</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>XUnit Tests, JetBrains Rider, and Counting Until Failure</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider&lt;/a&gt; is a fantastic tool, and full disclosure, as of writing this post, I am a developer advocate for JetBrains. &lt;a href=&quot;https://xunit.net&quot;&gt;XUnit&lt;/a&gt; is also an excellent unit testing framework, and their combined powers create an out-of-this-world testing experience.&lt;/p&gt;

&lt;p&gt;One feature JetBrains Rider users have fallen in love with is &lt;strong&gt;Run Selected Tests Until Failure&lt;/strong&gt;, which is what it sounds like. JetBrains Rider will continue executing your unit test until the test fails. The test runner feature can help diagnose finicky unit tests that work intermittently. Nothing is worse than an inconsistent bug, am I right?!&lt;/p&gt;

&lt;p&gt;When performing an investigation, you want as much information as possible. For example, a common question might be, “How many times did my test run before failing?”.&lt;/p&gt;

&lt;p&gt;In this post, we’ll build an XUnit fixture you can use in your tests to determine the number of iterations before a failure. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;xunit-unit-tests-and-fixtures&quot;&gt;XUnit Unit Tests and Fixtures&lt;/h2&gt;

&lt;p&gt;XUnit is a unit testing library that provides a framework for building a test suite. It’s a popular tool for many developers and is supported by all .NET IDE vendors. A technique to share functionality across unit tests is building a fixture. &lt;a href=&quot;https://xunit.net/docs/shared-context&quot;&gt;A fixture is a shared context between tests&lt;/a&gt;. This feature can help reduce the cost of expensive dependencies such as databases, Docker containers, and more.&lt;/p&gt;

&lt;p&gt;I prefer fixtures, but admittedly this approach could forgo fixtures in favor of a static class and static methods. If you like that approach, please modify the code accordingly.&lt;/p&gt;

&lt;p&gt;I’ll be using SQLite to store the count for each test execution. You’ll need to install the NuGet package of &lt;code&gt;Microsoft.Data.Sqlite&lt;/code&gt;. Let’s take a look at the fixture.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Runtime.CompilerServices;
using Microsoft.Data.Sqlite;

namespace FailCounter;

public class TestRunsCounter
{
    private const string ConnectionString = &quot;Data Source=tests.db&quot;;

    public TestRunsCounter()
    {
        using var connection = new SqliteConnection(ConnectionString);
        connection.Open();
        using var command = connection.CreateCommand();
        command.CommandText =
            &quot;&quot;&quot;
            CREATE TABLE IF NOT EXISTS Counts
            (
                Name  TEXT not null
                    constraint Name primary key,
                Count integer
            );
            &quot;&quot;&quot;;
        command.ExecuteNonQuery();
    }

    public long Increment([CallerMemberName] string? testName = null)
    {
        if (testName is null)
            return 0;

        using var connection = new SqliteConnection(ConnectionString);
        connection.Open();
        var command = connection.CreateCommand();
        command.CommandText =
            &quot;&quot;&quot;
            INSERT Into Counts (Name, Count) Values($name, 1)      
            On CONFLICT(Name) Do Update Set
                Count = Count + 1
                Where Name = $name;
            Select Count from Counts Where Name = $name;
            &quot;&quot;&quot;;
        command.Parameters.AddWithValue(&quot;$name&quot;, testName);
        var count = (long)command.ExecuteScalar()!;

        return count;
    }

    public void Reset([CallerMemberName] string? testName = null)
    {
        if (testName is null)
            return;

        using var connection = new SqliteConnection(ConnectionString);
        connection.Open();
        var command = connection.CreateCommand();
        command.CommandText =
            &quot;&quot;&quot;
            INSERT Into Counts (Name, Count) Values($name, 0)      
            On CONFLICT(Name) Do Update Set
                Count = 0
                Where Name = $name;
            &quot;&quot;&quot;;
        command.Parameters.AddWithValue(&quot;$name&quot;, testName);
        command.ExecuteNonQuery();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The calls to &lt;code&gt;Increment&lt;/code&gt; will either increment an existing row’s count or insert a new row with a count of 1. I also included a &lt;code&gt;Reset&lt;/code&gt; method for resetting counters during investigations. The &lt;code&gt;Reset&lt;/code&gt; method must be called manually by you.&lt;/p&gt;

&lt;h2 id=&quot;using-the-test-runs-counter-fixture&quot;&gt;Using The Test Runs Counter Fixture&lt;/h2&gt;

&lt;p&gt;Utilizing the &lt;code&gt;TestRunsCounter&lt;/code&gt; fixture is as straightforward as implementing the &lt;code&gt;IClassFixture&lt;/code&gt; interface. Let’s look at an example of using the counter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Xunit.Abstractions;

namespace FailCounter;

public class UnitTest1 : IClassFixture&amp;lt;TestRunsCounter&amp;gt;
{
    private readonly TestRunsCounter _fixture;
    private readonly ITestOutputHelper _output;

    public UnitTest1(TestRunsCounter fixture, ITestOutputHelper output)
    {
        _fixture = fixture;
        _output = output;
    }

    [Fact]
    public void Test1()
    {
        var count = _fixture.Increment();
        _output.WriteLine($&quot;Current count is \&quot;{count}\&quot;.&quot;);

        if (count &amp;gt; 10)
        {
            throw new Exception();
        }

        Assert.True(count &amp;lt; 10);
    }

    [Theory]
    [InlineData(nameof(Test1))]
    public void Reset(string testName)
        =&amp;gt; _fixture.Reset(testName);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can let JetBrains Rider run our test until failure. We can also use the unit test of &lt;code&gt;Reset&lt;/code&gt; to reset our failing test. Great!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Intermittently failing tests are frustrating, but with JetBrains Riders “Run Selected Tests Until Failure”, you can diagnose those pesky situations. By using SQLite, we can track the iterations it took to fail. You can also use this as a starting to serialize other stateful information from a unit test and store them in SQLite.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and let me know how you end up using this code in your code bases. As always, thank you.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 May 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/xunit-tests-jetbrains-rider-and-counting-until-failure</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/xunit-tests-jetbrains-rider-and-counting-until-failure</guid>
        
        <category>xunit,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Override Razor Pages Routes From Razor Class Libraries</title>
        <description>&lt;p&gt;Sharing is caring, and what’s more affectionate than sharing Razor Pages functionality with the .NET community? Well, a lot of other things, but sharing Razor Pages can help you deliver functionality to the other developers that would otherwise be difficult to integrate into existing applications.&lt;/p&gt;

&lt;p&gt;Some examples of practical Razor Page implementations might include a route debugger, an administrative panel, a terminal emulator, and a documentation renderer. All of these could be something you take on and ship to users to help accelerate their development and help them focus more on their problem domain.&lt;/p&gt;

&lt;p&gt;To accomplish this goal, you may use the Razor Class Library, which allows you to bundle Razor Pages, Razor Components, and other static assets. That said, there are bound to be conflicts with routes and users’ aesthetic senses of what routes should look like.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how you can override Razor Pages routes delivered from a Razor Class Library.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-a-razor-class-library&quot;&gt;What Is A Razor Class Library?&lt;/h2&gt;

&lt;p&gt;Razor Class Libraries (RCL) allow developers to share Razor components, C# code, and static assets to projects referencing the library. The approach is helpful for situations where you have standard functionality worth sharing in other projects but not necessarily repeating. Projects that can use an RCL include ASP.NET Core MVC, Blazor Server app, and Blazor WASM. You can distribute RCLs in multiple ways, but the most effective approach is through a NuGet package.&lt;/p&gt;

&lt;p&gt;You can create an RCL project using the .NET template &lt;code&gt;razorclasslib&lt;/code&gt; or the “New Project” facilities of your favorite .NET IDE.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-razor-class-library-for-razor-pages&quot;&gt;Creating A Razor Class Library For Razor Pages&lt;/h2&gt;

&lt;p&gt;To create an RCL, begin a new project within your solution using the .NET SDK-provided template. You’ll need two additional elements in your &lt;code&gt;.csproj&lt;/code&gt; file to support Razor Pages.&lt;/p&gt;

&lt;p&gt;First, let’s add the &lt;code&gt;AddRazorSupportForMvc&lt;/code&gt; element. In the &lt;code&gt;csrpoj&lt;/code&gt; file, you should add the following element to your project file’s first &lt;code&gt;PropertyGroup&lt;/code&gt; tag. This addition allows the RCL to support Razor Pages and the structure required to embed the files in the project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;AddRazorSupportForMvc&amp;gt;true&amp;lt;/AddRazorSupportForMvc&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following essential element is a &lt;code&gt;FrameworkReference&lt;/code&gt; in the same project file. The reference imports the ASP.NET Core primitives required by Razor pages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;FrameworkReference Include=&quot;Microsoft.AspNetCore.App&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Without this additional reference, you won’t be able to use classes like &lt;code&gt;PageModel&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;adding-a-razor-page&quot;&gt;Adding A Razor Page&lt;/h2&gt;

&lt;p&gt;In the RCL project, we will use &lt;strong&gt;Areas&lt;/strong&gt; to isolate our Razor Pages from a consuming project’s pages. The approach keeps conflicts at a minimum. We’ll add a custom “Privacy” Razor Page in an “Extra” area. The directory structure will look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;|- wwwroot
|- Areas
   |- Extra
      |- Pages    
         |- Privacy.cshtml 
         |- Privacy.cshtml.cs 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The contents of the Razor Page are not very important in this case. I reworked the namespaces and copied the default &lt;code&gt;Privacy&lt;/code&gt; page from an existing Razor Pages project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s the important part! Don’t skip this.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When defining your Razor Pages, &lt;em&gt;&lt;strong&gt;do not&lt;/strong&gt;&lt;/em&gt; set the route in your pages. Instead, each page should only have the &lt;code&gt;@page&lt;/code&gt; attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;// correct
@page
// incorrect
@page &quot;/privacy&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This decision will be necessary for letting users override their applications’ routes.&lt;/p&gt;

&lt;p&gt;In a referencing project, you should now be able to navigate to the page using &lt;code&gt;/Extra/Privacy&lt;/code&gt;, but what if you don’t do that? Well, let’s look at the crux of this post, overriding the route.&lt;/p&gt;

&lt;h2 id=&quot;overriding-rcl-razor-pages-routes&quot;&gt;Overriding RCL Razor Pages Routes&lt;/h2&gt;

&lt;p&gt;ASP.NET Core registers Razor Pages by their &lt;strong&gt;“page name”&lt;/strong&gt;. The page name is typically a version of the physical path combined with an area, if applicable.&lt;/p&gt;

&lt;p&gt;In our case, the route to our RCL Razor Page has a page name of &lt;code&gt;/Privacy&lt;/code&gt; and an area name of &lt;code&gt;Extra&lt;/code&gt;. We can use this information by adding a new convention to our Razor Pages options. The code is straightforward; you can add the following code in your &lt;code&gt;Program.cs&lt;/code&gt; or &lt;code&gt;Startup&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.Configure&amp;lt;RazorPagesOptions&amp;gt;(opt =&amp;gt;
{
    // Override an imported Razor Class Library
    // Razor Pages Route
    opt.Conventions.AddAreaPageRoute(
        areaName: &quot;Extra&quot;,
        pageName: &quot;/Privacy&quot;,
        route: &quot;/Privacy&quot;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instead of navigating to &lt;code&gt;/Extra/Privacy&lt;/code&gt;, you can get to the RCL Razor page using &lt;code&gt;/Privacy&lt;/code&gt;. Hooray!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s imperative that the author of the RCL did not set the &lt;code&gt;@page&lt;/code&gt; route, or else you will run into issues.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, you can generate routes using the link generation found in ASP.NET Core using the original page name and area name from the RCL library.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a asp-area=&quot;Extra&quot; asp-page=&quot;/Privacy&quot;&amp;gt;Privacy&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the resulting link will be the override route set in your &lt;code&gt;RazorPagesOptions&lt;/code&gt; instance. Great!&lt;/p&gt;

&lt;p&gt;An additional step you could take in your RCL implementation is providing an extension method on &lt;code&gt;IServiceCollection&lt;/code&gt; that sets the route in a more user-friendly manner.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;

namespace RazorPagesExtra.Extra;

public static class RoutesExtensions
{
    public static IServiceCollection SetPrivacyUrl(this IServiceCollection services, string route)
    {
        services.Configure&amp;lt;RazorPagesOptions&amp;gt;(opt =&amp;gt;
        {
            // Override an imported Razor Class Library
            // Razor Pages Route
            opt.Conventions.AddAreaPageRoute(
                areaName: &quot;Extra&quot;,
                pageName: &quot;/Privacy&quot;,
                route: route);
        });
        
        return services;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With a call in the referencing app, looking like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.SetPrivacyUrl(&quot;/Privacy&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this could be expanded to a configuration object instead. So you have unlimited options for how you’d like to approach this from here on out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: If you’re noticing your RCL page has no layout, you can always add a new &lt;code&gt;Areas&lt;/code&gt; folder in your referencing project with a &lt;code&gt;_ViewStart.cshtml&lt;/code&gt; file.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;@{
   /*
    *  |- wwwroot
    *  |- Areas
    *     |- _ViewStart.cshtml 
    */
   Layout = &quot;_Layout&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This additional file will set the Layout for all RCL libraries and let you use your project’s layout file.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Delivering value to other developers using RCLs is an excellent feature of ASP.NET Core, but sometimes users want control over their routes. Using Razor Pages conventions and excluding a default route, you can give your users the ability to override any route you provide via an RCL.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and as always, thank you for reading and sharing my work.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/OverrideRazorClassLibraryRoutes&quot;&gt;If you’d like to see a complete sample of this repository, you can see it on my GitHub repository.&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 16 May 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/override-razor-pages-routes-from-razor-class-libraries</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/override-razor-pages-routes-from-razor-class-libraries</guid>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Manage Vite Assets Like A Pro</title>
        <description>&lt;p&gt;I’ve recently been doing a lot of work with TypeScript and Vite, and one of the issues I’ve run into is my &lt;code&gt;vite.config.ts&lt;/code&gt; file can become a mess almost too quickly. Unfortunately, Vite’s strength of configurability is also its most significant barrier: so many options exist!&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how you can set up your Vite asset management to predictably place assets where you want them while taking advantage of Vite’s build pipeline to hash and chunk files. I’ll also introduce you to a Vite plugin that I think should be part of Vite out of the box.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;a-vite-project-and-goals&quot;&gt;A Vite Project and Goals&lt;/h2&gt;

&lt;p&gt;When starting a Vite-powered project, you’ll likely pick your frontend framework, possibly set up TypeScript, install external dependencies, and add assets like images, videos, and other static files. However, it’s important to note that Vite operates in what I refer to as a &lt;code&gt;split-mind&lt;/code&gt; approach. As a result, what happens in development mode differs from what you expect during the build process. Your development folder can have one organizational strategy, while your distribution folder takes an entirely different direction.&lt;/p&gt;

&lt;p&gt;Understanding and configuring where your final build artifacts end up is an optional feature of Vite, but taking the time to think through the process can set you up for success when deploying your app.&lt;/p&gt;

&lt;p&gt;For example, having images in a dedicated folder means you can more easily manage your static assets in a hosting environment. Additionally, some files, like RSS feeds, might not benefit from the hash and be counterproductive. Finally, having folders allows for CDN and syncing strategies at a higher level than a single folder or file.&lt;/p&gt;

&lt;p&gt;So, how do you manage your Vite assets? Let me show you.&lt;/p&gt;

&lt;h2 id=&quot;vite-assets-configuration&quot;&gt;Vite Assets Configuration&lt;/h2&gt;

&lt;p&gt;Vite options have a lot of methods and values you can override to create the particular behavior you seek. In short, you need to override the following Vite option values:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;build.rollupOptions.output.entryFileNames&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;build.rollupOptions.output.assetFileNames&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;build.rollupOptions.output.chunkFileNames&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While you could certainly set these values inline, you’ll find your &lt;code&gt;vite.config.ts&lt;/code&gt; file quickly becomes unruly. So what I did was create a file at &lt;code&gt;config/assets.ts&lt;/code&gt;. Let’s take a look at it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import {PreRenderedAsset} from &quot;rollup&quot;;

type AssetOutputEntry = {
    output: string,
    regex: RegExp
}

export const assetDir = &quot;assets&quot;;
export const entryFileNames = `${assetDir}/js/[name]-[hash].js`;
export const chunkFileNames = `${assetDir}/js/[name]-[hash]-chunk.js`
const assets: AssetOutputEntry[] = [
    {
        output: `${assetDir}/img/[name]-[hash][extname]`,
        regex: /\.(png|jpe?g|gif|svg|webp|avif)$/
    },
    {
        regex: /\.css$/,
        output: `${assetDir}/css/[name]-[hash][extname]`
    },
    {
        output: `${assetDir}/js/[name]-[hash][extname]`,
        regex: /\.js$/
    },
    {
        output: `[name][extname]`,
        regex: /\.xml$/
    }
];

export function processAssetFileNames(info: PreRenderedAsset): string {
    if (info &amp;amp;&amp;amp; info.name) {
        const name = info.name as string;
        const result = assets.find(a =&amp;gt; a.regex.test(name));
        if (result) {
            return result.output;
        }
    }
    // default since we don&apos;t have an entry
    return `${assetDir}/[name]-[hash][extname]`
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The file allows anyone to manage assets by setting a new &lt;code&gt;AssetOutputEntry&lt;/code&gt; item with a corresponding &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;regex&lt;/code&gt; value. As Vite finds new assets to process, the method &lt;code&gt;processAssetFileNames&lt;/code&gt; will be passed the information, at which point you can route the file to its final destination. Let’s see how you use this new file in your &lt;code&gt;vite.config.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import {defineConfig} from &quot;vite&quot;;
import {processAssetFileNames, entryFileNames, chunkFileNames, assetDir} from &quot;./config/assets&quot;;
import {resolve} from &quot;path&quot;;
import viteHtmlResolveAlias from &apos;vite-plugin-html-resolve-alias&apos;

export default defineConfig({

    resolve: {
        alias: {
            &apos;@img&apos;: resolve(__dirname, &apos;src/img/&apos;),
            &apos;@rss&apos;: resolve(__dirname, &apos;src/rss.xml&apos;)
        }
    },

    plugins: [
      viteHtmlResolveAlias()
    ],

    build: {
        minify: true,
        assetsDir: assetDir,
        // don&apos;t inline anything for demo
        assetsInlineLimit: 0,
        emptyOutDir: true,
        rollupOptions: {
            output: {
                entryFileNames: entryFileNames,
                assetFileNames: processAssetFileNames,
                chunkFileNames: chunkFileNames
            }
        }
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can manage all your assets from your &lt;code&gt;assets.ts&lt;/code&gt; file using regular expressions. Neat!&lt;/p&gt;

&lt;p&gt;Now let’s look at how we can use the assets in our HTML files.&lt;/p&gt;

&lt;h2 id=&quot;html-resolve-alias-vite-assets&quot;&gt;HTML Resolve Alias Vite Assets&lt;/h2&gt;

&lt;p&gt;You will want to use some assets in HTML and JavaScript files. For example, I’m using an image of &lt;code&gt;vite.svg&lt;/code&gt; in the &lt;code&gt;main.ts&lt;/code&gt; file and &lt;code&gt;index.html&lt;/code&gt; in this sample.&lt;/p&gt;

&lt;p&gt;Note: The following package says it’s incompatible with the latest Vite version, but it’s not. So you may need to perform an &lt;code&gt;npm install --force&lt;/code&gt; to get the package installed.&lt;/p&gt;

&lt;p&gt;Using the package &lt;code&gt;vite-plugin-html-resolve-alias&lt;/code&gt;, I can create resolution aliases that the plugin will process in my HTML files. But first, let’s see what setting up aliases looks like. You may have noticed the &lt;code&gt;resolve&lt;/code&gt; section in my previous configuration file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;resolve: {
    alias: {
        &apos;@img&apos;: resolve(__dirname, &apos;src/img/&apos;),
        &apos;@rss&apos;: resolve(__dirname, &apos;src/rss.xml&apos;)
    }
},
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are aliases to files found in my &lt;code&gt;src&lt;/code&gt; directory that I want to run through the Vite asset pipeline and use in TypeScript and HTML. To use these files in HTML, we can use our new aliases.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;&amp;lt;link rel=&quot;icon&quot; type=&quot;image/svg+xml&quot; href=&quot;@img/vite.svg&quot;/&amp;gt;
&amp;lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS Feed&quot; href=&quot;@rss&quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we call to build, these assets are processed similarly to any other asset imported in our TypeScript. Neat! Here’s a snippet from the final build output.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;link rel=&quot;icon&quot; type=&quot;image/svg+xml&quot; href=&quot;/assets/img/vite-4a748afd.svg&quot;&amp;gt;
&amp;lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS Feed&quot; href=&quot;/rss.xml&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Depending on the use case, I’m no longer hampered by duplicate assets in &lt;code&gt;public&lt;/code&gt; or &lt;code&gt;src&lt;/code&gt;. I can use the same asset in both static HTML and dynamic JavaScript. That’s a win-win!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Vite’s asset pipeline is robust, especially for folks building web applications. With some care and thought, you can decide how assets are processed and where they end up in the final distribution folder.&lt;/p&gt;

&lt;p&gt;If you’d like to see a working sample of this blog post, &lt;a href=&quot;https://github.com/khalidabuhakmeh/vite-asset-management&quot;&gt;I’ve uploaded it to my GitHub repository, where you can see the build in action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you found this post helpful, and let me know what you think. As always, thanks for reading and sharing my posts. Cheers.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 May 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/manage-vite-assets-like-a-pro</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/manage-vite-assets-like-a-pro</guid>
        
        <category>vite,</category>
        
        <category>typescript</category>
        
        
      </item>
    
      <item>
        <title>Running Vite with ASP.NET Core Web Applications</title>
        <description>&lt;p&gt;The web ecosystem constantly ebbs and flows between simplicity and complexity. The nature of an ever-evolving development model makes it essential to keep your tooling updated, or else you find yourself stranded on a “maintenance island”. The current tool du jour is Vite, and I find the decisions made with it a refreshing net positive for the frontend development toolkit. It’s one of the more straightforward tooling options in the ecosystem with sane defaults but ultimate reconfigurability.&lt;/p&gt;

&lt;p&gt;While the frontend ecosystem is handily winning the UI/UX development conversation, there’s also a lot that ASP.NET Core’s Razor can offer application developers, and it’s arguably a better option to rely on both when building user-facing applications.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how to integrate Vite’s development server with ASP.NET Core, and you’ll be surprised it’s much simpler than you may think. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;whats-vite&quot;&gt;What’s Vite?&lt;/h2&gt;

&lt;p&gt;Before jumping into ASP.NET code, let’s talk about &lt;a href=&quot;https://vitejs.dev&quot;&gt;&lt;strong&gt;Vite&lt;/strong&gt;&lt;/a&gt; and how it can help your development workflow. Vite is a development environment for developers using various frameworks, such as React, Angular, Vue, and other libraries. Vite also is “smart” and can recognize common development dependencies, such as TypeScript and Sass, giving developers a low-ceremony approach to adding the dependencies to their projects. Finally, Vite is compatible with Rollup plugins to process other assets, such as images, styles, and HTML.&lt;/p&gt;

&lt;p&gt;For developers, Vite operates in two modes: &lt;code&gt;development&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt;. Vite’s &lt;code&gt;development&lt;/code&gt; mode utilizes hot-module reload capabilities to provide developers with immediate feedback when assets change on disk. This mode increases the feedback-loop time, increasing developer productivity. It also allows developers to see unprocessed assets to improve the ability to debug issues.&lt;/p&gt;

&lt;p&gt;During the &lt;code&gt;build&lt;/code&gt; mode, assets are processed through plugins and ultimately readied for deployment. The build includes all referenced JavaScript, Stylesheets, and HTML files. Additionally, Vite copies all static assets to the final build directory.&lt;/p&gt;

&lt;p&gt;In summary, Vite is a development tool that simplifies an increasingly complex frontend ecosystem, and I believe it works. Check out the official site to learn more. https://vitejs.dev/&lt;/p&gt;

&lt;h2 id=&quot;adding-vite-to-aspnet-core&quot;&gt;Adding Vite To ASP.NET Core&lt;/h2&gt;

&lt;p&gt;The first step to adding Vite to your ASP.NET Core applications is getting all your files and folders in the right place. The two most essential elements will be where you place your &lt;code&gt;package.json&lt;/code&gt; and your frontend development folder. I named my development folder &lt;code&gt;Client&lt;/code&gt;, but feel free to call it whatever you’d like.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Project
|- wwwroot
|- /Client
  |- /public
  |- /src
  |- main.ts
|- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In your &lt;code&gt;packages.json&lt;/code&gt;, you’ll add all your development dependencies, with the most critical being &lt;code&gt;vite&lt;/code&gt; and &lt;code&gt;typescript&lt;/code&gt; (if you want to use TypeScript). Here’s my &lt;code&gt;package.json&lt;/code&gt; file for my sample project, including my &lt;code&gt;scripts&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;my-webcomponents&quot;,
  &quot;private&quot;: true,
  &quot;version&quot;: &quot;0.0.0&quot;,
  &quot;type&quot;: &quot;module&quot;,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;vite&quot;,
    &quot;build&quot;: &quot;tsc &amp;amp;&amp;amp; vite build&quot;,
    &quot;preview&quot;: &quot;vite preview&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;ts-node&quot;: &quot;^10.9.1&quot;,
    &quot;typescript&quot;: &quot;^5.0.2&quot;,
    &quot;vite&quot;: &quot;^4.2.0&quot;,
    &quot;bootstrap&quot;: &quot;^5.2.3&quot;,
    &quot;jquery&quot;: &quot;^3.6.4&quot;,
    &quot;jquery-validation&quot;: &quot;^1.19.5&quot;,
    &quot;jquery-validation-unobtrusive&quot;: &quot;^4.0.0&quot;,
    &quot;sass&quot;: &quot;^1.61.0&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we need both the &lt;code&gt;tsconfig.json&lt;/code&gt; and &lt;code&gt;vite.config.ts&lt;/code&gt; files at the root of our project. Here are mine, respectively.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;compilerOptions&quot;: {
    &quot;composite&quot;: true,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;lib&quot;: [&quot;ES2020&quot;, &quot;DOM&quot;, &quot;DOM.Iterable&quot;],
    &quot;declaration&quot;: true,
    &quot;emitDeclarationOnly&quot;: true,
    &quot;outDir&quot;: &quot;./Client/types&quot;,
    &quot;strict&quot;: true,
    &quot;noUnusedLocals&quot;: true,
    &quot;noUnusedParameters&quot;: true,
    &quot;noImplicitReturns&quot;: true,
    &quot;noFallthroughCasesInSwitch&quot;: true,
    &quot;moduleResolution&quot;: &quot;Node&quot;,
    &quot;isolatedModules&quot;: true,
    &quot;allowSyntheticDefaultImports&quot;: true,
    &quot;experimentalDecorators&quot;: true,
    &quot;forceConsistentCasingInFileNames&quot;: true,
    &quot;useDefineForClassFields&quot;: false,
    &quot;skipLibCheck&quot;: true,
    &quot;types&quot;: [
      &quot;vite/client&quot;
    ]
  },
  &quot;include&quot;: [
    &quot;vite.config.ts&quot;,
    &quot;Client&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;vite.config.ts&lt;/code&gt; file is a bit of a doozy, but it’s written to support the same HTTPS certificate your ASP.NET Core application will use by loading settings from your &lt;code&gt;appSettings&lt;/code&gt; files.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;/**
 * Name: vite.config.ts
 * Description: Vite configuration file
 */

import { UserConfig, defineConfig } from &apos;vite&apos;;
import { spawn } from &quot;child_process&quot;;
import fs from &quot;fs&quot;;
import path from &quot;path&quot;;

// @ts-ignore
import appsettings from &quot;./appsettings.json&quot;;
// @ts-ignore
import appsettingsDev from &quot;./appsettings.Development.json&quot;;

import * as process from &quot;process&quot;;

// Get base folder for certificates.
const baseFolder =
    process.env.APPDATA !== undefined &amp;amp;&amp;amp; process.env.APPDATA !== &apos;&apos;
        ? `${process.env.APPDATA}/ASP.NET/https`
        : `${process.env.HOME}/.aspnet/https`;

// Generate the certificate name using the NPM package name
const certificateName = process.env.npm_package_name;

// Define certificate filepath
const certFilePath = path.join(baseFolder, `${certificateName}.pem`);
// Define key filepath
const keyFilePath = path.join(baseFolder, `${certificateName}.key`);

// Pattern for CSS files
const cssPattern = /\.css$/;
// Pattern for image files
const imagePattern = /\.(png|jpe?g|gif|svg|webp|avif)$/;

// Export Vite configuration
export default defineConfig(async () =&amp;gt; {
  // Ensure the certificate and key exist
  if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
    // Wait for the certificate to be generated
    await new Promise&amp;lt;void&amp;gt;((resolve) =&amp;gt; {
      spawn(&apos;dotnet&apos;, [
        &apos;dev-certs&apos;,
        &apos;https&apos;,
        &apos;--export-path&apos;,
        certFilePath,
        &apos;--format&apos;,
        &apos;Pem&apos;,
        &apos;--no-password&apos;,
      ], { stdio: &apos;inherit&apos;, })
          .on(&apos;exit&apos;, (code: any) =&amp;gt; {
            resolve();
            if (code) {
              process.exit(code);
            }
          });
    });
  };

  // Define Vite configuration
  const config: UserConfig = {
    clearScreen: true,
    appType: &apos;mpa&apos;,
    root: &apos;Client&apos;,
    publicDir: &apos;public&apos;,
    build: {
      manifest: appsettings.Vite.Manifest,
      emptyOutDir: true,
      outDir: &apos;../wwwroot&apos;,
      assetsDir: &apos;&apos;,
      rollupOptions: {
        input: [&apos;Client/main.ts&apos;, &quot;Client/scss/site.scss&quot; ],
        // remove hashing, but I could add it back in
        output: {
          // Save entry files to the appropriate folder
          entryFileNames: &apos;js/[name].js&apos;,
          // Save chunk files to the js folder
          chunkFileNames: &apos;js/[name]-chunk.js&apos;,
          // Save asset files to the appropriate folder
          assetFileNames: (info) =&amp;gt; {
            if (info.name) {
              // If the file is a CSS file, save it to the css folder
              if (cssPattern.test(info.name)) {
                return &apos;css/[name][extname]&apos;;
              }
              // If the file is an image file, save it to the images folder
              if (imagePattern.test(info.name)) {
                return &apos;images/[name][extname]&apos;;
              }

              // If the file is any other type of file, save it to the assets folder 
              return &apos;assets/[name][extname]&apos;;
            } else {
              // If the file name is not specified, save it to the output directory
              return &apos;[name][extname]&apos;;
            }
          },
        }
      },
    },
    server: {
      port: appsettingsDev.Vite.Server.Port,
      strictPort: true,
      https: {
        cert: certFilePath,
        key: keyFilePath
      },
      hmr: {
        host: &quot;localhost&quot;,
        clientPort: appsettingsDev.Vite.Server.Port
      }
    }
  }

  return config;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Feel free to modify the &lt;code&gt;vite.config.ts&lt;/code&gt; to match your use case. For example, I removed the hash from all build artifacts, but you may want to add them back.&lt;/p&gt;

&lt;p&gt;You’ll also want to modify the &lt;code&gt;input&lt;/code&gt; array to produce the required files on the build. In my case, I want to build both my site’s CSS and JavaScript as separate assets.&lt;/p&gt;

&lt;p&gt;If you get stuck configuring your Vite configuration, I suggest you read the Vite documentation to see all available options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note: The build assets should end up in &lt;code&gt;wwwroot&lt;/code&gt; so ASP.NET Core can bundle and publish them correctly. Also, modify your &lt;code&gt;csproj&lt;/code&gt; to include any files on publish. As this is project specific, you’ll need to figure this out independently.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, we must modify our &lt;code&gt;appsettings.json&lt;/code&gt; and &lt;code&gt;appsettings.Development.json&lt;/code&gt; files. So here they are, respectively.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft.AspNetCore&quot;: &quot;Warning&quot;
    }
  },
  &quot;AllowedHosts&quot;: &quot;*&quot;,
  &quot;Vite&quot;: {
    &quot;Manifest&quot;: &quot;assets.manifest.json&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And The development settings, which includes a &lt;code&gt;Vite&lt;/code&gt; section. Here we will tell the Middleware what port the Vite dev server will be listening on. You can also set the script name here, but by default, the Vite middleware will look for a script named &lt;strong&gt;&lt;code&gt;dev&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;DetailedErrors&quot;: true,
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft.AspNetCore&quot;: &quot;Warning&quot;
    }
  },
  &quot;Vite&quot;: {
    &quot;Server&quot;: {
      &quot;Port&quot;: 5173,
      &quot;Https&quot;: true
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s install the NuGet package of &lt;code&gt;Vite.AspNetCore&lt;/code&gt; by adding it to our project’s &lt;code&gt;csproj&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;PackageReference Include=&quot;Vite.AspNetCore&quot; Version=&quot;1.4.0&quot; /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you’ve installed the package, register the services and Middleware in your ASP.NET Core application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddViteDevMiddleware();
}
// Add the Vite Manifest Service.
builder.Services.AddViteManifest();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here’s the registration for Middleware.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;if (app.Environment.IsDevelopment())
{
    app.UseViteDevMiddleware();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is my complete &lt;code&gt;Program.cs&lt;/code&gt; file, so you can see where to place each code block.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Vite.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddViteDevMiddleware();
}
// Add the Vite Manifest Service.
builder.Services.AddViteManifest();

// Add services to the container.
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(&quot;/Error&quot;);
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();

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

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There’s one more step, which is to connect the client to our Vite development server. We must modify the &lt;code&gt;_Layout.cshtml&lt;/code&gt; page with additional &lt;code&gt;environment&lt;/code&gt; tags to do that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;&amp;lt;environment include=&quot;Development&quot;&amp;gt;
    &amp;lt;!-- Vite development server script --&amp;gt;
    &amp;lt;script type=&quot;module&quot; src=&quot;~/@@vite/client&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script defer type=&quot;module&quot; src=&quot;~/main.ts&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/environment&amp;gt;
&amp;lt;environment include=&quot;Production&quot;&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;~/@Manifest[&quot;scss/site.scss&quot;]!.File&quot; asp-append-version=&quot;true&quot;/&amp;gt;
    &amp;lt;script defer type=&quot;module&quot; src=&quot;~/@Manifest[&quot;main.ts&quot;]!.File&quot; asp-append-version=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/environment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code block in your layout will depend on your &lt;code&gt;vite.config.ts&lt;/code&gt; file and the resulting assets in your manifest. The &lt;code&gt;Vite.AspNetCore&lt;/code&gt; package comes with a helpful manifest helper, so you don’t have to know what the artifact name will be on the build, you use the source name instead, and it finds the correct name for you.&lt;/p&gt;

&lt;p&gt;If you’ve followed my steps correctly, you should now have an ASP.NET Core application talking to the Vite development server. You can also change any asset and see Vite’s HMR update your page immediately. Very cool!&lt;/p&gt;

&lt;h2 id=&quot;caveats&quot;&gt;Caveats&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Vite.AspNetCore&lt;/code&gt; project isn’t waiting for the Vite server to start, so initial page loads may not immediately connect to the server. I’ll be attempting to submit a pull request to fix this issue. If you don’t see your assets on the page, try reloading your page.&lt;/p&gt;

&lt;p&gt;A Vite caveat, you must import Sass assets in your JavaScript or TypeScript files to take advantage of hot module reloads.&lt;/p&gt;

&lt;p&gt;Vite configuration is a dense topic. While the defaults work in most situations, reading more about the topic, precisely things like Rollup plugins, doesn’t hurt.&lt;/p&gt;

&lt;p&gt;You may want to exclude your &lt;code&gt;wwwroot&lt;/code&gt; from source control, as running the &lt;code&gt;build&lt;/code&gt; locally will create and change those files every time. In addition, churn can add a lot of noise to your pull requests and make code reviews a headache.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Vite is a powerful development tool for folks building frontend experiences. The &lt;code&gt;Vite.AspNetCore&lt;/code&gt; Middleware is an excellent option for folks who want to merge their front and back end into a single process. I want to thank the author &lt;a href=&quot;https://github.com/Eptagone&quot;&gt;Quetzal Rivera&lt;/a&gt; for taking the time to create the package so the community can benefit from their work.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/AspNetCoreLitWebComponents&quot;&gt;I’ve created a working solution at my GitHub repository if you want to see a functioning sample.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As always, thanks for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 02 May 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/running-vite-with-aspnet-core-web-applications</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/running-vite-with-aspnet-core-web-applications</guid>
        
        <category>vite,</category>
        
        <category>aspnetcore</category>
        
        
      </item>
    
      <item>
        <title>Unit Test 11ty Pages With Vitest and Typescript</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://www.11ty.dev&quot;&gt;11ty&lt;/a&gt; (pronounced eleventy) is the most incredible static site generator available to the JavaScript community. It’s powerful, flexible, and has just enough opinions to make you immediately productive while letting you and your team build the development workflow of your dreams.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore unit testing your 11ty views if you’ve decided to use a combination of Typescript/JavaScript templates mixed with string literals. Of course, this approach also works with JSX, which I’ll use in the code below. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;javascript-template-language&quot;&gt;JavaScript Template Language&lt;/h2&gt;

&lt;p&gt;While 11ty offers a multitude of template languages, folks who are comfortable writing JavaScript and appreciate tooling help should consider using TypeScript and &lt;a href=&quot;https://www.11ty.dev/docs/languages/javascript/&quot;&gt;the JavaScript template language&lt;/a&gt; features of 11ty.&lt;/p&gt;

&lt;p&gt;While I adore templating languages like Liquid, Nunjucks, and Mustache, tooling can sometimes fall short in these contexts, providing you with little information about your data model and what fields are accessible. On the other hand, when working with JavaScript templates, tooling can effectively introspect types, function parameters, and much more. The JavaScript template approach can help you identify issues before they spiral out of control. You can take it further and create all your templates using TypeScript.&lt;/p&gt;

&lt;p&gt;Let’s see what a JavaScript template declaration might look like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class Test {
  // or `async data() {`
  // or `get data() {`
  data() {
    return {
      name: &quot;Ted&quot;,
      layout: &quot;teds-rad-layout&quot;,
      // … other front matter keys
    };
  }

  render({name}) {
    // will always be &quot;Ted&quot;
    return `&amp;lt;p&amp;gt;${name}&amp;lt;/p&amp;gt;`;
  }
}

module.exports = Test;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, a few things are happening in the previous code.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;There is a &lt;code&gt;data&lt;/code&gt; getter that returns the template’s “frontmatter”.&lt;/li&gt;
  &lt;li&gt;There is a &lt;code&gt;render&lt;/code&gt; method that returns HTML.&lt;/li&gt;
  &lt;li&gt;All methods are in a &lt;code&gt;class&lt;/code&gt; definition.&lt;/li&gt;
  &lt;li&gt;All methods support &lt;code&gt;sync&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; implementations.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;data()&lt;/code&gt; has access to &lt;code&gt;this&lt;/code&gt;, an &lt;code&gt;EleventyPage&lt;/code&gt; instance; the &lt;code&gt;render&lt;/code&gt; method also has access to &lt;code&gt;this&lt;/code&gt; along with the page’s frontmatter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Awesome! So how do you write a test for this class?&lt;/p&gt;

&lt;h2 id=&quot;writing-tests-for-11ty-javascript-templates&quot;&gt;Writing Tests For 11ty JavaScript Templates&lt;/h2&gt;

&lt;p&gt;First of all, you need to pick a unit testing environment. For simplicity’s sake, I used a combination of &lt;code&gt;Vite&lt;/code&gt; and &lt;code&gt;Vitest&lt;/code&gt;. I will also be using TypeScript to get an enhanced tooling experience.&lt;/p&gt;

&lt;p&gt;Let’s look at the template we’ll be unit testing. I’ve created an &lt;code&gt;Example.tsx&lt;/code&gt; file to use JSX.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-react&quot;&gt;import h, {JSX} from &quot;vhtml&quot;;

export class Example {
    data(): Context {
        return {
            // @ts-ignore, 11ty shortcode
            greeting: this.lower(&quot;Hi&quot;)
        }
    }

    render(this: MyThis, context: Context) : JSX.Element {
        // VIP over here
        return this.name === &apos;Khalid&apos;
            ? (&amp;lt;h1&amp;gt;{context.greeting} {this.name}&amp;lt;/h1&amp;gt;)
            : (&amp;lt;h6&amp;gt;{context.greeting} {this.name}&amp;lt;/h6&amp;gt;)
    }
}

export type MyThis = { name: string; lower: Function; }
export type Context = { greeting : string }

module.exports = Example;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m also defining expected types for &lt;code&gt;this&lt;/code&gt;, which you can get from the parameters list of each method, or you can use &lt;code&gt;this&lt;/code&gt; implicitly.&lt;/p&gt;

&lt;p&gt;Knowing that we’re looking for specific data, we can now use our types for better tooling support and a better idea of how to stub out functionality and required data. So now, let’s take a look at the test.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// @ts-ignore
import h, {JSX} from &quot;vhtml&quot;;
import {expect, it} from &quot;vitest&quot;;
import { Example } from &quot;./Example&quot;;

it(&apos;can set this on render method&apos;, () =&amp;gt; {
    const example = new Example();
    const myThis = {
        name: &quot;Khalid&quot;,
        lower: (i: string) =&amp;gt; i.toLowerCase()
    };

    const data = example.data.apply(myThis);
    const result = example.render.apply(myThis, [ data ]);

    expect(result).to.equal(&quot;&amp;lt;h1&amp;gt;hi Khalid&amp;lt;/h1&amp;gt;&quot;)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The vital part of the test is taking the methods of our template, in this case, it’s &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;render&lt;/code&gt;, and using the &lt;code&gt;apply&lt;/code&gt; method to change the &lt;code&gt;this&lt;/code&gt; on each method call.&lt;/p&gt;

&lt;p&gt;The advantage to this approach is that you can now stub and replace any functionality within your templates. In addition, using types makes it relatively straightforward to test different data scenarios, such as no elements in a collection instead of some elements.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are a lot of template language choices in the 11ty toolbox, and I think you should try them all. They each have strengths and weaknesses, but it’s great that they’re all built on top of a core set of 11ty data objects. If you need to unit test your templates for complex visual logic, consider the JavaScript template language, as it’s easy to verify and fix bugs using this approach. I should note that unit tests should be an addition to your testing strategy and that you should always confirm your work by running it through 11ty itself.&lt;/p&gt;

&lt;p&gt;Well, I hope you enjoyed this post, and as always, thank you for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 25 Apr 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/unit-test-11ty-pages-with-vitest-and-typescript</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/unit-test-11ty-pages-with-vitest-and-typescript</guid>
        
        <category>TypeScript,</category>
        
        <category>11ty</category>
        
        
      </item>
    
      <item>
        <title>Writing a Cross-Platform Clock App With Avalonia UI and NXUI</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://www.avaloniaui.net/&quot;&gt;Avalonia UI&lt;/a&gt; has been a refreshing reprieve from my typical web development workflows. Of course, the web will always be my first love, but I’m enjoying the ease and intuitiveness of desktop app development. Additionally, the Avalonia team has put extraordinary work into making a truly cross-platform development experience. So if you want to build your first Avalonia-powered application, this post might be just for you.&lt;/p&gt;

&lt;p&gt;I’ll be using the &lt;a href=&quot;https://github.com/wieslawsoltes/NXUI&quot;&gt;NXUI library&lt;/a&gt; written by &lt;a href=&quot;https://github.com/wieslawsoltes&quot;&gt;Wiesław Šoltés&lt;/a&gt;. If you’re allergic to XAML, this library might be your detour to desktop development, as it relies on a fluent interface to define views while retaining the APIs that make XAML so expressive.&lt;/p&gt;

&lt;p&gt;So, let’s get started!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-nxui&quot;&gt;What is NXUI?&lt;/h2&gt;

&lt;p&gt;NXUI is an attempt to bring the trend of minimalism to desktop application development built around the Avalonia UI API. As author, Wiesław Šoltés states in the NXUI readme:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Creating minimal Avalonia next generation (NXUI, next-gen UI) application using C# 10 and .NET 6 and 7&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what does the code of a next-generation Avalonia application look like?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Window Build() =&amp;gt; Window().Content(Label().Content(&quot;NXUI&quot;));

AppBuilder.Configure&amp;lt;Application&amp;gt;()
  .UsePlatformDetect()
  .UseFluentTheme()
  .StartWithClassicDesktopLifetime(Build, args);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow! That’s relatively minimal, but let’s write something more useful. How about a clock? It’s time to write some code (pun intended).&lt;/p&gt;

&lt;p&gt;To start building your first NXUI application, you’ll need to add the following to a .NET console app’s &lt;code&gt;.csproj&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;NXUI&quot; Version=&quot;11.0.0-preview5&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note: the version might differ when searching on NuGet. Be sure to use the latest version of the package.&lt;/p&gt;

&lt;h2 id=&quot;an-avalonia-ui-clock-app&quot;&gt;An Avalonia UI Clock App&lt;/h2&gt;

&lt;p&gt;NXUI relies heavily on &lt;code&gt;Observable&lt;/code&gt; elements to hydrate dynamic values in a view. In the case of our demo, we’ll be using the &lt;code&gt;System.Timers.Timer&lt;/code&gt; class to create a new string value using the current &lt;code&gt;DateTime.Now&lt;/code&gt; result. Let’s see how you create an &lt;code&gt;Observable&amp;lt;string&amp;gt;&lt;/code&gt; that returns values on a specified interval.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var currentTime = Observable.Create&amp;lt;string&amp;gt;(
    observer =&amp;gt;
    {
        var timer = new System.Timers.Timer {
            Interval = 250,
        };
        timer.Elapsed += (_, _) =&amp;gt; observer.OnNext($&quot;{DateTime.Now:hh:mm:ss tt}&quot;);
        timer.Start();
        return Disposable.Empty;
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When working with NXUI, you’ll often use the &lt;code&gt;Observable.Create&lt;/code&gt; method for dynamic values. You can also refactor many calls into separate classes and helper methods.&lt;/p&gt;

&lt;p&gt;Next, let’s Build our view, which will hold our time string.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;Window Build() =&amp;gt;
    Window()
        .Width(400).Height(200).CanResize(false)
        .WindowStartupLocation(WindowStartupLocation.CenterScreen)
        .Content(
            Border()
                .Margin(25, 0, 25, 0)
                .Height(100)
                .CornerRadius(10)
                .BoxShadow(BoxShadows.Parse(&quot;5 5 10 2 Black&quot;))
                .Background(Brushes.White)
                .Child(
                    TextBlock()
                        .Foreground(Brushes.Black)
                        .TextAlignmentCenter()
                        .ZIndex(1)
                        .FontSize(40)
                        .FontStretch(FontStretch.Expanded)
                        .VerticalAlignment(VerticalAlignment.Center)
                        // Set The Observable&amp;lt;string&amp;gt; to Text
                        .Text(currentTime)
                )
        );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We have a window with a single &lt;code&gt;Border&lt;/code&gt; element, which wraps our &lt;code&gt;TextBlock&lt;/code&gt;. The most important aspect of our code is that the call to &lt;code&gt;TextBlock.Text&lt;/code&gt; takes our &lt;code&gt;currentTime&lt;/code&gt; argument. As the timer ticks, the UI will update with our latest value.&lt;/p&gt;

&lt;p&gt;The code for this demo is a tight 40 lines of code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var currentTime = Observable.Create&amp;lt;string&amp;gt;(
    observer =&amp;gt;
    {
        var timer = new System.Timers.Timer {
            Interval = 250,
        };
        timer.Elapsed += (_, _) =&amp;gt; observer.OnNext($&quot;{DateTime.Now:hh:mm:ss tt}&quot;);
        timer.Start();
        return Disposable.Empty;
    });

Window Build() =&amp;gt;
    Window()
        .Width(400).Height(200).CanResize(false)
        .WindowStartupLocation(WindowStartupLocation.CenterScreen)
        .Content(
            Border()
                .Margin(25, 0, 25, 0)
                .Height(100)
                .CornerRadius(10)
                .BoxShadow(BoxShadows.Parse(&quot;5 5 10 2 Black&quot;))
                .Background(Brushes.White)
                .Child(
                    TextBlock()
                        .Foreground(Brushes.Black)
                        .TextAlignmentCenter()
                        .ZIndex(1)
                        .FontSize(40)
                        .FontStretch(FontStretch.Expanded)
                        .VerticalAlignment(VerticalAlignment.Center)
                        // Set The Observable&amp;lt;string&amp;gt; to Text
                        .Text(currentTime)
                )
        );

AppBuilder
    .Configure&amp;lt;Application&amp;gt;()
    .UsePlatformDetect()
    .UseFluentTheme()
    .StartWithClassicDesktopLifetime(Build, args);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running our code, we see a functioning clock application. Pretty cool! (The image reflects the clock from the final sample).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/khalidabuhakmeh/AvaloniaClock/raw/main/screenshot.png&quot; alt=&quot;Avalonia Clock&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The most fantastic part of Avalonia has been the rich ecosystem of folks building different ways to make the technology accessible. If you like XAML, then that’s great. If you want C#, there are also ways to access Avalonia. If you’re an F# person, there are also folks working on F# implementations of Avalonia. NXUI is one of many approaches in the Avalonia ecosystem. The fluent interface made it a little more accessible to discover the properties of components and how they might tie together.&lt;/p&gt;

&lt;p&gt;If you’d like to play around with the code found in this post, I’ve pushed up a complete working &lt;a href=&quot;https://github.com/khalidabuhakmeh/AvaloniaClock&quot;&gt;Avalonia Clock sample at my GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Tue, 18 Apr 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/writing-a-cross-platform-clock-app-with-avalonia-ui-and-nxui</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/writing-a-cross-platform-clock-app-with-avalonia-ui-and-nxui</guid>
        
        <category>avalonia,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Dependency Injection with Avalonia UI Apps</title>
        <description>&lt;p&gt;I’ve recently been experimenting with &lt;a href=&quot;https://www.avaloniaui.net/&quot;&gt;Avalonia UI&lt;/a&gt;, a development framework for desktop and mobile platforms, and I’ve been enjoying the experience. While Avalonia has much to offer out of the box, it is more than happy to let you make many decisions. One of those decisions is whether to use dependency injection as a part of your application.&lt;/p&gt;

&lt;p&gt;In this experimental post, we’ll see how I added dependency injection into an ongoing Avalonia application and discuss the pros and cons of the approach.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;registering-your-dependencies&quot;&gt;Registering Your Dependencies&lt;/h2&gt;

&lt;p&gt;Since no infrastructure exists for user-defined dependency injection in Avalonia (or at least non that I am aware of), we must create our own. The first step to any dependency injection approach is finding and registering all our dependencies.&lt;/p&gt;

&lt;p&gt;For the post, &lt;a href=&quot;https://jasperfx.github.io/lamar/&quot;&gt;I’m using Lamar&lt;/a&gt;, the spiritual successor of StructureMap. Of course, you can substitute your own, but I like Lamar’s interface for scanning and registering types.&lt;/p&gt;

&lt;p&gt;I added the following code in &lt;code&gt;Program.cs&lt;/code&gt; of my Avalonia app.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static IContainer Container { get; }

static Program()
{
    Container = new Container(cfg =&amp;gt;
    {
        cfg.Scan(scan =&amp;gt;
        {
            scan.AssemblyContainingType&amp;lt;Program&amp;gt;();
            scan.AddAllTypesOf&amp;lt;ViewModelBase&amp;gt;();
            scan.AddAllTypesOf&amp;lt;IControl&amp;gt;();
            scan.WithDefaultConventions();
        });
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code scans my application for all types of &lt;code&gt;ViewModelBase&lt;/code&gt; and &lt;code&gt;IControl&lt;/code&gt; along with the default conventions of Lamar. A sane default is registering concrete types against their first interface. Now that we set up our dependency graph let’s start changing our view models and views.&lt;/p&gt;

&lt;h2 id=&quot;windowbase-and-viewmodelbase&quot;&gt;WindowBase and ViewModelBase&lt;/h2&gt;

&lt;p&gt;Using the Model-View-ViewModel approach, I must create base classes for my views and viewmodels. Let’s look at both now, starting with my &lt;code&gt;WindowBase&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Avalonia.Controls;
using HelloAvalonia.ViewModels;
using Lamar;

namespace HelloAvalonia.Views;

public abstract class WindowBase&amp;lt;T&amp;gt; : Window
    where T: ViewModelBase
{
    [SetterProperty]
    public T ViewModel
    {
        get =&amp;gt; (T)DataContext!;
        set =&amp;gt; DataContext = value;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice I’m using an attribute called &lt;code&gt;SetterProperty&lt;/code&gt; on a new &lt;code&gt;ViewModel&lt;/code&gt; property. As Lamar builds our Window, it will also resolve the ViewModel and set the &lt;code&gt;DataContext&lt;/code&gt;. &lt;strong&gt;I opted to use property injection to allow the Avalonia preview tool to continue working in JetBrains Rider.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s look at our &lt;code&gt;ViewModelBase&lt;/code&gt; implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using CommunityToolkit.Mvvm.ComponentModel;

namespace HelloAvalonia.ViewModels;

public abstract class ViewModelBase : ObservableObject
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m using the &lt;strong&gt;&lt;a href=&quot;https://github.com/CommunityToolkit/dotnet&quot;&gt;CommunityToolkit.Mvvm&lt;/a&gt;&lt;/strong&gt; package, so my ViewModels inherit from &lt;code&gt;ObservableObject&lt;/code&gt;. Now, let’s implement a view model instance.&lt;/p&gt;

&lt;h2 id=&quot;mainwindow-mainwindowviewmodel-and-dependencies&quot;&gt;MainWindow, MainWindowViewModel, and Dependencies&lt;/h2&gt;

&lt;p&gt;Like our &lt;code&gt;ViewModel&lt;/code&gt; property in our &lt;code&gt;WindowBase&lt;/code&gt; class, we’ll resolve all dependencies using the &lt;code&gt;SetterProperty&lt;/code&gt; attribute. First, let’s change our main view to inherit from WindowBase. The change will ensure our &lt;code&gt;DataContext&lt;/code&gt; is set as our container creates the instance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using HelloAvalonia.ViewModels;
using Lamar;

namespace HelloAvalonia.Views;

public partial class MainWindow : WindowBase&amp;lt;MainWindowViewModel&amp;gt;
{
    public MainWindow()
    {
        InitializeComponent();
    }
        
    [SetterProperty]
    public DialogWindow? Dialog { get; set; }

    public Action ShowDialogInteraction =&amp;gt; 
        () =&amp;gt; Dialog?.ShowDialog(this);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I will also need another dialog window to show some other information. For example, I can ask for any control registered in my container.&lt;/p&gt;

&lt;p&gt;In this example, I’m using the dialog instance to create an interaction and pass it to my view model to keep controls out of my business logic.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Button
    Content=&quot;Show Dialog&quot;
    Command=&quot;{Binding ShowDialogCommand}&quot;
    CommandParameter=&quot;{Binding #Main.ShowDialogInteraction}&quot;
    HorizontalAlignment=&quot;Center&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let’s see the &lt;code&gt;MainWindowViewModel&lt;/code&gt; implementation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace HelloAvalonia.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
    [ObservableProperty, NotifyPropertyChangedFor(nameof(PlayAnimation))]
    private int _count;

    [ObservableProperty]
    private bool _isEnabled = true;

    [ObservableProperty] private string _text = &quot;Click Me&quot;;
    public bool PlayAnimation =&amp;gt; Count &amp;gt; 0 &amp;amp;&amp;amp; Count % 2 == 0;

    [RelayCommand]
    private void Click()
    {
        Count++;
        Text = Count == 1
            ? $&quot;Clicked {Count} time&quot;
            : $&quot;Clicked {Count} times&quot;;
    } 

    [RelayCommand]
    private void ShowDialog(Action? showDialogInteraction)
    {
        showDialogInteraction?.Invoke();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are no dependencies here, but we pass our interaction to our &lt;code&gt;ShowDialog&lt;/code&gt; method. So what’s the dialog implementation look like?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using HelloAvalonia.ViewModels;

namespace HelloAvalonia.Views;

public partial class DialogWindow : WindowBase&amp;lt;DialogWindowViewModel&amp;gt;
{
    public DialogWindow()
    {
        InitializeComponent();
    }
    
    public Action HideInteraction =&amp;gt; Hide;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the View Model is even simpler.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using System.Threading.Tasks;
using Avalonia.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HelloAvalonia.Models;
using Lamar;

namespace HelloAvalonia.ViewModels;

public partial class DialogWindowViewModel : ViewModelBase
{
    [SetterProperty] 
    public ICatsImageService? Cats { get; set; }

    [ObservableProperty] private Bitmap? _catImage;

    [RelayCommand]
    private async Task Opened()
    {
        if (Cats is { })
        {
            var bitmap = await Cats.GetRandomImage();
            CatImage = bitmap;
        }
    }

    [RelayCommand]
    private void Hide(Action? interaction)
    {
        CatImage = null;
        interaction?.Invoke();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We are injecting an instance of &lt;code&gt;ICatsImageService&lt;/code&gt; using Lamar’s &lt;code&gt;SetterProperty&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;So now that we have our views and viewmodels, where is our entry point?&lt;/p&gt;

&lt;h2 id=&quot;the-entrypoint&quot;&gt;The Entrypoint&lt;/h2&gt;

&lt;p&gt;The entry point of an Avalonia app occurs in the &lt;code&gt;App&lt;/code&gt; implementation. Therefore, I modify the &lt;code&gt;OnFrameworkInitializationCompleted&lt;/code&gt; method to use the container I define in &lt;code&gt;Program&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using HelloAvalonia.Views;

namespace HelloAvalonia;

public partial class App : Application
{
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {
        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            desktop.MainWindow = 
                Program
                .Container
                .GetInstance&amp;lt;MainWindow&amp;gt;();
        }

        base.OnFrameworkInitializationCompleted();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it! We now have a working application.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Some folks hate dependency injection, and some folks love it. I think it has value in complex applications where you want to define “how” things are set up in one place and forget about it. With Avalonia, it takes a bit of work to get started with dependency injection, but not too much.&lt;/p&gt;

&lt;p&gt;It’s essential to be mindful of the lifetimes of your controls and their dependencies. As you’re dealing with a desktop application, I don’t see a need to create multiple instances of objects, so Singleton registrations should work fine in most cases.&lt;/p&gt;

&lt;p&gt;Well, I hope you liked this post. I’ve included the code to this &lt;a href=&quot;https://github.com/khalidabuhakmeh/HelloAvalonia&quot;&gt;Avalonia UI sample on my GitHub repository&lt;/a&gt; for you to try.&lt;/p&gt;
</description>
        <pubDate>Tue, 11 Apr 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dependency-injection-with-avalonia-ui-apps</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dependency-injection-with-avalonia-ui-apps</guid>
        
        <category>avalonia,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Load YouTube Embed Videos When Needed With JavaScript</title>
        <description>&lt;p&gt;If you’re a content creator or work on a site that heavily relies on YouTube embeds, you’ll quickly realize that they can dramatically impact the load time of a page. Load times can also grow depending on the number of YouTube embeds on a page.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see a technique to reduce page load times by using newer HTML and JavaScript techniques to load videos when the user needs them.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-are-youtube-embeds-slowing-my-page-load-times&quot;&gt;Why Are YouTube Embeds Slowing My Page Load Times&lt;/h2&gt;

&lt;p&gt;YouTube videos typically have a thumbnail image displayed to the user before the video starts. YouTube may serve up to four thumbnails, all varying in quality. Unfortunately for performance, most browsers treat images as blocking elements on a page. Regarding performance, this means the page cannot complete loading unless the element is also loaded.&lt;/p&gt;

&lt;p&gt;There have been recent techniques to mitigate this issue, including adding a &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; to images so the client can calculate the layout in advance of the image loading and the use of the &lt;code&gt;lazy&lt;/code&gt; attribute to signify that you’re willing to load the asset outside of the critical rendering path. That’s great, right?!&lt;/p&gt;

&lt;p&gt;Well, YouTube embeds utilize an &lt;code&gt;iframe&lt;/code&gt; where you don’t have control over the markup or attributes. So how do you get around this issue? You cheat… sort of.&lt;/p&gt;

&lt;h2 id=&quot;using-plyr-for-youtube-embeds&quot;&gt;Using Plyr For YouTube Embeds&lt;/h2&gt;

&lt;p&gt;In my use case, I had over 42 YouTube images on a page, with only one visible at a time. That’s a lot of image requests to YouTube’s thumbnail service, making my page understandably slow to load.&lt;/p&gt;

&lt;p&gt;My first step was to use a video player other than that of YouTube’s iframe embed. In my case, I used &lt;a href=&quot;https://plyr.io/&quot;&gt;&lt;strong&gt;Plyr&lt;/strong&gt;&lt;/a&gt;. It’s pretty straightforward to use the library with existing YouTube content.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div class=&quot;video-player&quot; 
     data-plyr-provider=&quot;vimeo&quot; 
     data-plyr-embed-id=&quot;76979871&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the HTML in place, you must create an instance of the &lt;code&gt;Plyr&lt;/code&gt; JavaScript class for each occurrence of an embedded video.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const players = Array
    .from(document.querySelectorAll(&apos;.video-player&apos;))
    .map((p) =&amp;gt; new Plyr(p));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this suffers from the same issue as before, so we need to be smarter here. You’ll see how to solve this same issue in the next section.&lt;/p&gt;

&lt;h2 id=&quot;using-intersectionobserver-to-create-plyr-instances&quot;&gt;Using IntersectionObserver To Create Plyr Instances&lt;/h2&gt;

&lt;p&gt;Our goal is only to instantiate &lt;code&gt;Plyr&lt;/code&gt; instances that the user sees. We can accomplish this using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; type&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport. –Mozilla&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For our use case, we’ll monitor our video elements’ visibility and call &lt;code&gt;new Plyr&lt;/code&gt; once.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// import Plyr dependency
import Plyr from &quot;plyr&quot;;

// simplified onVisible method
const onVisible = function (element, callback) {
  const  options = {
    root: document,
  };
  const observer = new IntersectionObserver((entries, observer) =&amp;gt; {
    entries.forEach((entry) =&amp;gt; {
      callback(entry, observer);
    });
  }, options);
  observer.observe(element);
};

// create an array of video player HTML elements
const videos = Array.from(document.querySelectorAll(&quot;.video-player&quot;));
// apply onVisible callback
videos.forEach((video) =&amp;gt; {
  onVisible(video, (entry, observer) =&amp;gt; {
    if (entry.intersectionRatio &amp;gt; 0) {
      new Plyr(entry.target);
      observer.unobserve(entry.target);
    }
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The vital part of this code is the implementation of the callback for each element.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt; if (entry.intersectionRatio &amp;gt; 0) {
      new Plyr(entry.target);
      observer.unobserve(entry.target);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once we create the video player, we no longer need to observe its changes, as we’ve loaded all assets, and the video is ready for the user. Now videos are created when the user needs them, not on the initial page load.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;IntersectionObserver&lt;/code&gt; technique, my page load times went from several seconds to milliseconds. In addition, I improved performance and kept users happy with just a few lines of JavaScript.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Web development is easy to get into but takes a lifetime to master, especially as the APIs and features of HTML, JavaScript, and CSS improve. Also, when working with third parties, finding solutions around their implementations can be challenging. Luckily, you can always load things when needed rather than all at once. This technique can also be used for other network-heavy and blocking resources.&lt;/p&gt;

&lt;p&gt;I hope you found this post interesting and helpful. As always, thank you for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 04 Apr 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/load-youtube-embed-videos-with-javascript</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/load-youtube-embed-videos-with-javascript</guid>
        
        <category>html</category>
        
        
      </item>
    
      <item>
        <title>.NET MAUI App Stopped Working -- HELP!</title>
        <description>&lt;p&gt;So you’ve spent several weeks successfully developing a Multi-Application UI app. Then, suddenly, your IDE shows that your application has hundreds of errors, and you cannot build. What’s going on?!&lt;/p&gt;

&lt;p&gt;This post is an ongoing list of issues you might encounter while developing MAUI apps that seem to break your app for inexplicable “reasons”. Finally, I’ll suggest potential fixes to get you back into the development flow.&lt;/p&gt;

&lt;p&gt;Let’s Get Started!&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;everything-is-screaming-red-and-broken&quot;&gt;Everything Is Screaming Red and Broken!&lt;/h2&gt;

&lt;p&gt;If you were successfully developing your application and suddenly your solution failed to load, you likely have changed your environment. &lt;strong&gt;Failed MAUI solutions indicate a change in the .NET SDK.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, you may have been developing successfully using the .NET 7 SDK and wanted to try the latest .NET 8 preview SDK. Unfortunately, after installing the SDK, everything is broken! Ahhh!&lt;/p&gt;

&lt;p&gt;The problem is the easiest fix among the issues I’ve seen with MAUI. To fix the issue,  add a &lt;code&gt;global.json&lt;/code&gt; file at the root of your solution to tie your project back to the correct SDK band and to access the SDK band’s workloads.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;sdk&quot;: {
    &quot;version&quot;: &quot;7.0.0&quot;,
    &quot;rollForward&quot;: &quot;latestMinor&quot;,
    &quot;allowPrerelease&quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You may need to restart your editor, but you should be back in business upon restart.&lt;/p&gt;

&lt;h2 id=&quot;build-fails-with-one-or-more-invalid-files-were-detected&quot;&gt;Build Fails with One or More Invalid Files Were Detected&lt;/h2&gt;

&lt;p&gt;So you decided to import some new resources to pretty up your MAUI application. Unfortunately, you’ll get this error message after importing, and you’re confused. Is it my new files?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;Microsoft.Maui.Resizetizer.targets(525, 9): One or more invalid file names were detected. File names must be lowercase, start and end with a letter character, and contain only alphanumeric characters or underscores: 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Deleting the new assets doesn’t fix your issue, and now your app is perpetually broken. Aaaaaah!&lt;/p&gt;

&lt;p&gt;Well, have no fear. The error is another straightforward problem with a clear solution. MacOS users may have touched the files in the asset folder, creating a &lt;code&gt;.DS_Store&lt;/code&gt; file that’s typically invisible in the solution explorer and Finder. However, you’ll see the file if you look at the &lt;strong&gt;Images&lt;/strong&gt; folder using something like JetBrains Rider File Explorer.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/dotnet-maui-app-work/jetbrains-rider-maui-file-system-ds-store.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/dotnet-maui-app-work/jetbrains-rider-maui-file-system-ds-store.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_478/https://khalidabuhakmeh.com/assets/images/posts/dotnet-maui-app-work/jetbrains-rider-maui-file-system-ds-store.png 478w&quot; sizes=&quot;100vw&quot; alt=&quot;File System in JetBrains Rider showing .DS_Store file in MAUI App&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;350&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Delete this file, and you’ll be back in business.&lt;/p&gt;

&lt;p&gt;You can also resolve this issue by changing your MAUI project’s &lt;code&gt;MauiImage&lt;/code&gt; wildcard in the &lt;code&gt;.csproj&lt;/code&gt; only to include file extensions for known image types.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Images --&amp;gt;
&amp;lt;MauiImage Include=&quot;Resources\Images\*.{png,svg}&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can recreate the &lt;code&gt;.DS_Store&lt;/code&gt; issue by running &lt;code&gt;touch&lt;/code&gt; from the command line, which creates the offending file.&lt;/p&gt;

&lt;h2 id=&quot;pass-selectitem-to-my-view-model-command&quot;&gt;Pass SelectItem to My View Model Command&lt;/h2&gt;

&lt;p&gt;While not an issue, this one left me scratching my head for a bit, and I thought I’d save you the trouble of scratching your head. &lt;strong&gt;How do you bind a &lt;code&gt;SelectItem&lt;/code&gt; from a &lt;code&gt;CollectionView&lt;/code&gt; to a &lt;code&gt;CommandParameter&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re using an MVVM framework, like &lt;code&gt;CommunityToolkit.Mvvm&lt;/code&gt;, you likely have a command on your view model that needs information from a user event like &lt;code&gt;SelectionChanged&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The trick to this solution is to add a name to your component, then use the &lt;code&gt;Source&lt;/code&gt; attribute to reference the item. It will make more sense when you look at the XAML.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;CollectionView
    x:Name=&quot;TodosCollectionView&quot;
    VerticalOptions=&quot;Fill&quot;
    ItemsSource=&quot;{Binding Items}&quot;
    SelectionMode=&quot;Single&quot;
    SelectionChangedCommand=&quot;{Binding SelectionChangedCommand}&quot;
    SelectionChangedCommandParameter=&quot;{Binding SelectedItem, Source={x:Reference TodosCollectionView}}&quot;&amp;gt;
...
&amp;lt;/CollectionView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;communitytoolkitmvvm-cant-find-my-properties-or-commands&quot;&gt;CommunityToolkit.Mvvm Can’t Find My Properties or Commands&lt;/h2&gt;

&lt;p&gt;CommunityToolkit.Mvvm uses source generators and requires an environment to read and generate the additional source code of your view models. The generated code includes properties and &lt;code&gt;IAsyncRelayCommand&lt;/code&gt; implementations. If you cannot find these elements in your code, you likely have one of the following issues in your code base.&lt;/p&gt;

&lt;p&gt;You forgot the &lt;code&gt;partial&lt;/code&gt; keyword on your view model.
The name of your view model is &lt;em&gt;not&lt;/em&gt; the same name as the generated command. For example, an &lt;code&gt;OnAddItem&lt;/code&gt; method with &lt;code&gt;RelayCommandAttribute&lt;/code&gt; will create an &lt;code&gt;AddItemCommand&lt;/code&gt; command.
Try cleaning your &lt;code&gt;obj&lt;/code&gt; and &lt;code&gt;bin&lt;/code&gt; folders, which might fix the current state of your project. By clean, I mean delete them from your disk.
Restart your IDE.&lt;/p&gt;

&lt;h2 id=&quot;my-maui-app-never-starts-what-gives&quot;&gt;My MAUI App Never Starts! What Gives?!&lt;/h2&gt;

&lt;p&gt;If you’re using the dependency injection facility of MAUI, you must register all dependencies as part of your &lt;code&gt;MauiProgram&lt;/code&gt; file. Check your development environments console output for mentions of the following error.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;System.InvalidOperationException: Unable to resolve service for type...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The solution is to register the missing type in &lt;code&gt;MauiProgram&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddSingleton&amp;lt;AppShell&amp;gt;();
builder.Services.AddSingleton&amp;lt;MainPage&amp;gt;();
builder.Services.AddSingleton&amp;lt;MainPageModel&amp;gt;();
builder.Services.AddSingleton&amp;lt;TodoItemPage&amp;gt;();
builder.Services.AddSingleton&amp;lt;TodoItemPageModel&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As a suggestion, you may want to create a convention to register pages and their corresponding view models automatically.&lt;/p&gt;

&lt;h2 id=&quot;my-maui-build-is-slow&quot;&gt;My MAUI Build is Slow!&lt;/h2&gt;

&lt;p&gt;If you’re running a build for every target framework in your &lt;code&gt;TargetFrameworks&lt;/code&gt; tag, you’ll get some slow builds.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;net7.0-ios;net7.0-maccatalyst;net7.0-android;&amp;lt;/TargetFrameworks&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In my case, iOS is the fastest build, so I remove a few target frameworks until I’m ready to work on Android.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;net7.0-ios&amp;lt;TargetFrameworks&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to put in the additional effort, you can use environment variables and MSBuild flags to create different builds for different situations.&lt;/p&gt;

&lt;p&gt;The downside to this approach is you can inadvertently build something that works in iOS that is completely broken on other platforms before you realize it.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Developing with MAUI can be fun, but opaque errors are inevitable. I hope some of the problems and solutions outlined in this post can get you back on track.&lt;/p&gt;

</description>
        <pubDate>Tue, 28 Mar 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dotnet-maui-app-stopped-working-help</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dotnet-maui-app-stopped-working-help</guid>
        
        <category>MAUI,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>.NET MAUI Development Environment Set Up Walkthrough</title>
        <description>&lt;p&gt;Last year &lt;a href=&quot;https://blog.jetbrains.com/dotnet/2022/05/25/macos-environment-setup-for-maui-development/&quot;&gt;I wrote macOS Environment Setup for MAUI Development&lt;/a&gt; for the JetBrains .NET blog, and while many folks have told me they still find it helpful, it is, admittedly, out of date. So in this post, I’ll give you a shorter and more manageable guide to setting up your development environment for Multi-platform App UI (MAUI) in 2023.&lt;/p&gt;

&lt;p&gt;I’ve helped several folks set up their macOS environment with this updated guide, and it should mostly apply to a Windows environment (outside of the OS-specific SDKs).&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;installing-the-net-sdk&quot;&gt;Installing the .NET SDK&lt;/h2&gt;

&lt;p&gt;The first and most obvious step is you’ll need to install the latest .NET SDK. Head over to &lt;a href=&quot;https://dot.net&quot;&gt;https://dot.net&lt;/a&gt; and download the latest MAUI-supported SDK. As of writing this article, that is .NET 7.&lt;/p&gt;

&lt;p&gt;The SDK is necessary as dotnet will install and manage MAUI workloads according to SDK version bands.&lt;/p&gt;

&lt;p&gt;Once you’ve installed the .NET SDK, we’ll focus on the next important step.&lt;/p&gt;

&lt;h2 id=&quot;installing-xcode-for-maui&quot;&gt;Installing XCode for MAUI&lt;/h2&gt;

&lt;p&gt;You’ll need to install XCode, ensuring that MAUI supports the version of XCode you are installing. &lt;strong&gt;For .NET 7, the current version of XCode is 14.2.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recommend installing XCode using the Apple AppStore, as it’s the more straightforward method. You’ll want to pick Apple SDKs for iOS and macOS when installed. Other SDKs for Apple Watch and Apple TV are optional.&lt;/p&gt;

&lt;p&gt;Start up XCode and open the application’s settings. Next, you’ll need to navigate to Locations and ensure that Xcode is the correct value in the Command Line Tools select dropdown. If the dropdown has no value, be sure to select one. These tools help compile native assemblies for Apple device targets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-locations.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;XCode Locations tab in settings&quot; loading=&quot;lazy&quot; width=&quot;1660&quot; height=&quot;1100&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While you’re here, check your Platforms tab to ensure you have all the SDKs installed correctly.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/xcode-platforms.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;Xcode platforms tab showing installed Platforms of iOS and mac&quot; loading=&quot;lazy&quot; width=&quot;1660&quot; height=&quot;1080&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You’re good to go with XCode.&lt;/p&gt;

&lt;h2 id=&quot;installing-xamarinios-and-xamarinmacos&quot;&gt;Installing Xamarin.iOS and Xamarin.macOS&lt;/h2&gt;

&lt;p&gt;You’ll also want to install the latest Xamarin SDKs since MAUI still uses these. Visual Studio for Mac and Visual Studio ship these with each release, but you can install them without those apps. These SDKs also ship with JetBrains Rider’s plugins but can be outdated for MAUI development.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/xamarin/xamarin-macios/blob/main/DOWNLOADS.md&quot;&gt;You can download the latest Xamarin.iOS and Xamarin.mac packages here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll only need the package for the environments you are targeting, but you’re already installing gigabytes of dependencies, so what’s a few more?&lt;/p&gt;

&lt;h2 id=&quot;installing-maui-workloads&quot;&gt;Installing MAUI Workloads&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Important! Add a &lt;code&gt;global.json&lt;/code&gt; file with the correct SDK band you’ll be building MAUI apps.&lt;/strong&gt; For example, in the case of this guide, you’re working with .NET 7. So your &lt;code&gt;global.json&lt;/code&gt; file should look like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;sdk&quot;: {
    &quot;version&quot;: &quot;7.0.0&quot;,
    &quot;rollForward&quot;: &quot;latestMajor&quot;,
    &quot;allowPrerelease&quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you only have one SDK installed, you can skip this file. However, remember that you’ll need this file if you install any other SDKs.&lt;/p&gt;

&lt;p&gt;Workloads include all the necessary assemblies and MSBuild targets that make building a mobile application possible for a given platform. For example, most developers will want to target iOS, Android, and Mac Catalyst.&lt;/p&gt;

&lt;p&gt;Run the following commands in a new terminal. Note you’ll need elevated administrator permissions to complete this step.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo dotnet workload install maui
sudo dotnet workload install maui-android maui-ios maui-maccatalyst
sudo dotnet workload install ios android maccatalyst
sudo dotnet workload install wasm-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you install all these workloads, you can double-check that everything went accordingly using the command &lt;code&gt;dotnet workload list&lt;/code&gt;. You can also find other workloads using the dotnet workload search command.&lt;/p&gt;

&lt;h2 id=&quot;installing-microsoft-openjdk&quot;&gt;Installing Microsoft OpenJDK&lt;/h2&gt;

&lt;p&gt;You’ll need an OpenJDK installation to build and work with Android. I’ve found that &lt;a href=&quot;https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-11&quot;&gt;Microsoft’s OpenJDK 11.0.18 LTS works best with MAUI&lt;/a&gt;. &lt;a href=&quot;https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-11&quot;&gt;You can find the download here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You might need to set the &lt;code&gt;JAVA_HOME&lt;/code&gt; environment variable on your environment to point to the location of the newly installed OpenJDK. This step is optional if you use an IDE like &lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This next step is to get Android SDKs configured.&lt;/p&gt;

&lt;h2 id=&quot;installing-android-sdks&quot;&gt;Installing Android SDKs&lt;/h2&gt;

&lt;p&gt;This next step requires Android Studio, or if you’re a JetBrains Rider user, these same features also exist in that product. We’ll be using JetBrains products to install Android SDKs.&lt;/p&gt;

&lt;p&gt;Note to JetBrains Rider users, you’ll need to &lt;a href=&quot;https://plugins.jetbrains.com/plugin/12056-rider-xamarin-android-support&quot;&gt;install the Rider Xamarin Android Support plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a JetBrains Rider user, you’ll want to check your environments tab to ensure all environments are installed or recognized.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-environments.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;JetBrains Rider&apos;s Environment Tab showing all installed or recognized requirments&quot; loading=&quot;lazy&quot; width=&quot;2104&quot; height=&quot;1400&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, under the Android section in JetBrains Rider (or Android Studio), you’ll want to install the SDK that matches your MAUI install. As of writing this post, that version is 33. Find the Install new button and walk through the installation.&lt;/p&gt;

&lt;p&gt;Once completed, go back to the Android section and choose SDK Components. Here, you’ll select the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Android 13.0 (Tiramasu)&lt;/strong&gt; under SDK Platforms&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NDK (Side-by-side)&lt;/strong&gt; under SDK Tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When downloads and installation are complete, finish this process by ensuring the paths are set correctly on your Android settings page. This dialog is also where you’ll set the path to the OpenJDK 11 install from earlier.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/android-settings-tab.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;Android Settings tab&quot; loading=&quot;lazy&quot; width=&quot;2104&quot; height=&quot;1400&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;simulators-and-emulators&quot;&gt;Simulators and Emulators&lt;/h2&gt;

&lt;p&gt;For iOS, you’ll want to start your simulator at least once before trying any MAUI development. I recommend this step because the first time you boot an iOS simulator, it takes a minute to prepare everything. Start XCode, use the settings menu &lt;code&gt;XCode &amp;gt; Open Developer Tool&lt;/code&gt;, and select “Simulator”.&lt;/p&gt;

&lt;p&gt;In JetBrains Rider, this is the time to set up a new Android device emulator. Search for Device Manager and set up a new device. You can also choose to attach a physical Android device. That’s up to you.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/jetbrains-rider-device-manager.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;JetBrains Rider Device Manager showing Android Device&quot; loading=&quot;lazy&quot; width=&quot;2522&quot; height=&quot;1650&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You’ll need these virtual devices for testing your MAUI applications.&lt;/p&gt;

&lt;h2 id=&quot;your-first-maui-app&quot;&gt;Your First MAUI App&lt;/h2&gt;

&lt;p&gt;Phew! We’re at the finish line! Yay! Hopefully, you followed every step meticulously, and I didn’t miss anything obvious. But, honestly, this is a lot to take in, especially if it’s your first attempt at mobile app development.&lt;/p&gt;

&lt;p&gt;Now you can create a new MAUI app and run it in the environment of your choice.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1200/https://khalidabuhakmeh.com/assets/images/posts/maui-dev-enviornment-dotnet/maui-running-ios.png 1200w&quot; sizes=&quot;100vw&quot; alt=&quot;Running iOS simulator showing a MAUI app and JetBrains Rider&quot; loading=&quot;lazy&quot; width=&quot;2964&quot; height=&quot;2160&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you get build errors, don’t panic. Remember, you need a &lt;code&gt;global.json&lt;/code&gt; file to tie your new solution to the correct SDK version band. Scroll back up and use the same &lt;code&gt;global.json&lt;/code&gt; file from the previous section.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Hopefully, I covered every step necessary to build iOS and Android MAUI apps in your development environment. Of course, if you’re on Windows, you might have different challenges, but most of this guide still applies to you for Android development. Of course, you’ll still need Windows workloads to target MAUI for Windows. Use the &lt;code&gt;dotnet workload search&lt;/code&gt; to find the appropriate packages.&lt;/p&gt;

&lt;p&gt;Anyways, if you found this post helpful, I’m happy for you. You got a working MAUI environment, and that’s no tiny feet. So take this time to bask in your success. You deserve it.&lt;/p&gt;

&lt;p&gt;If you need help, you can find me on Mastodon or contact me through the form on this site. Cheers :)&lt;/p&gt;

</description>
        <pubDate>Tue, 21 Mar 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/dotnet-maui-development-environment-set-up-walkthrough</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/dotnet-maui-development-environment-set-up-walkthrough</guid>
        
        <category>dotnet,</category>
        
        <category>maui</category>
        
        
      </item>
    
      <item>
        <title>Solving .NET JSON Deserialization Issues</title>
        <description>&lt;p&gt;What is more frustrating than a sem-working solution, am I right? Unfortunately, when it comes to JSON serialization, that can mean getting some of the data sometimes. You’re left scratching your head and asking, “Why is my data not coming through correctly?”&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore the different &lt;code&gt;JsonSerializerOptions&lt;/code&gt; you might run into with .NET and how you can predict the behavior of your serialization. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;starting-with-plain-old-json&quot;&gt;Starting With Plain-old JSON&lt;/h2&gt;

&lt;p&gt;When working with JSON, two parties are typically involved: The producer and the consumer. Unfortunately, more often than not, when running into JSON deserialization issues, we often find that we misunderstood the producer’s JSON format and likely misconfigured something on our end. Let’s look at an example response from a hypothetical JSON API.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;[
   {
      &quot;name&quot;: &quot;Khalid Abuhakmeh&quot;,
      &quot;hobby&quot; : &quot;Video Games&quot;
   },
   {
      &quot;name&quot;: &quot;Maarten Balliauw&quot;,
      &quot;hobby&quot; : &quot;Gardening&quot; 
   }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a few characteristics to note about this response.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The top-level element is an array.&lt;/li&gt;
  &lt;li&gt;There are multiple elements in the array. Two, to be exact.&lt;/li&gt;
  &lt;li&gt;All fields are quoted.&lt;/li&gt;
  &lt;li&gt;All field names are camel-cased.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To process this JSON response, we need to set up our serialization options to match the JSON serialization choices of our producer. In the next section, let’s look at ways to fail and succeed at deserialization.&lt;/p&gt;

&lt;h2 id=&quot;attempting-to-deserialize-json&quot;&gt;Attempting to Deserialize JSON&lt;/h2&gt;

&lt;p&gt;The first likely step folks will take to use the &lt;code&gt;JsonSerializer&lt;/code&gt; class as is, with a straight call to &lt;code&gt;Deserialize&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var @default = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json);
Console.WriteLine($&quot;default: {@default?[0]}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m sad to say this is &lt;strong&gt;incorrect&lt;/strong&gt;, as the default serializer options work from “PascalCase”. So the result of this deserialization will produce entities, but their values will be null or empty.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;default: Person { Name = , Hobby =  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oops! Where are the &lt;code&gt;Name&lt;/code&gt; and the &lt;code&gt;Hobby&lt;/code&gt;? Well, it turns out that we have a naming mismatch. So how do we fix this issue? There are a few options.&lt;/p&gt;

&lt;p&gt;The first way to fix this issue is to use a different set of options for the &lt;code&gt;JsonSerializer&lt;/code&gt;. For example, we can use the &lt;code&gt;JsonSerializerDefaults&lt;/code&gt; class to choose the &lt;code&gt;Web&lt;/code&gt; option.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// camelCase
var web = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json,
    new JsonSerializerOptions(JsonSerializerDefaults.Web));
Console.WriteLine($&quot;web: {web?[0]}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Choosing the &lt;code&gt;JsonSerializerDefaults.Web&lt;/code&gt; value for &lt;code&gt;JsonSerializerOptions&lt;/code&gt; defaults to the camel case for all JSON field names. Running the code above, we have corrected our initial issues.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;web: Person { Name = Khalid Abuhakmeh, Hobby = Video Games }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What if we have an unreliable producer, and they may inadvertently change their mind about casing? Well, there’s one more option.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// any Case
var any = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json,
    new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
Console.WriteLine($&quot;case insensitive: {any?[0]}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This option will ignore casing on field names and map accordingly but be warned. Ignoring the case sensitivity of names will cause issues if the producer uses the same name for different fields. Running the code sample, we get the following result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;case insensitive: Person { Name = Khalid Abuhakmeh, Hobby = Video Games }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool! The solution still works, but there’s still one more solution to look over.&lt;/p&gt;

&lt;p&gt;You’ll likely use the &lt;code&gt;HttpClient&lt;/code&gt; class when working with JSON APIs. The &lt;code&gt;HttpClient&lt;/code&gt; uses the &lt;code&gt;JsonSerializerDefaults.Web&lt;/code&gt; options internally, so you don’t need any additional changes if you’re calling a camel-cased API.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// stubbing the web request to return the JSON
var httpClient = new HttpClient(new StubHandler(json));

// uses JsonSerializerOptions(JsonSerializerDefaults.Web) by default
var response = await httpClient.GetFromJsonAsync&amp;lt;Person[]&amp;gt;(&quot;https://example.com&quot;);
Console.WriteLine($&quot;http client: {response?[0]}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running this code, we see the results we expect.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;http client: Person { Name = Khalid Abuhakmeh, Hobby = Video Games }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also pass in any options to override the default behavior of the &lt;code&gt;GetFromJsonAsync&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var otherResponse = await httpClient.GetFromJsonAsync&amp;lt;Person[]&amp;gt;(
    &quot;https://example.com&quot;,
    new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
Console.WriteLine($&quot;http client w/ options: {otherResponse?[0]}&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running this sample, we still see the correct results.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;http client w/ options: Person { Name = Khalid Abuhakmeh, Hobby = Video Games }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, there we have it—a run-down of solving your serialization/deserialization issues when working with existing JSON APIs. I’ve included the complete solution below if you’d like to work with this sample.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts.&lt;/p&gt;

&lt;hr /&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Net;
using System.Net.Http.Json;
using System.Text.Json;

// language=json
var json = &quot;&quot;&quot;
[
   {
      &quot;name&quot;: &quot;Khalid Abuhakmeh&quot;,
      &quot;hobby&quot; : &quot;Video Games&quot;
   },
   {
      &quot;name&quot;: &quot;Maarten Balliauw&quot;,
      &quot;hobby&quot; : &quot;Gardening&quot; 
   }
]
&quot;&quot;&quot;;

// PascalCase
var @default = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json);
Console.WriteLine($&quot;default: {@default?[0]}&quot;);

// CamelCase
var web = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json,
    new JsonSerializerOptions(JsonSerializerDefaults.Web));
Console.WriteLine($&quot;web: {web?[0]}&quot;);

// any Case
var any = JsonSerializer.Deserialize&amp;lt;Person[]&amp;gt;(json,
    new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
Console.WriteLine($&quot;case insensitive: {any?[0]}&quot;);

// stubbing the web request to return the JSON
var httpClient = new HttpClient(new StubHandler(json));

// uses JsonSerializerOptions(JsonSerializerDefaults.Web) by default
var response = await httpClient.GetFromJsonAsync&amp;lt;Person[]&amp;gt;(&quot;https://example.com&quot;);
Console.WriteLine($&quot;http client: {response?[0]}&quot;);

var otherResponse = await httpClient.GetFromJsonAsync&amp;lt;Person[]&amp;gt;(
    &quot;https://example.com&quot;,
    new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
Console.WriteLine($&quot;http client w/ options: {otherResponse?[0]}&quot;);

// ReSharper disable once ClassNeverInstantiated.Global
public record Person(string Name, string Hobby);

public class StubHandler : DelegatingHandler
{
    private readonly string _response;

    public StubHandler(string response)
    {
        _response = response;
    }

    protected override Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(_response),
            RequestMessage = request
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;
</description>
        <pubDate>Tue, 14 Mar 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/solving-dotnet-json-deserialization-issues</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/solving-dotnet-json-deserialization-issues</guid>
        
        <category>dotnet,</category>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Validating Connection Strings on .NET Startup</title>
        <description>&lt;p&gt;There exist extension points in .NET that allow you to verify the starting state of your application. Validating configuration can be helpful when you know that without certain elements, there’s no reason to start the application. One of those configuration values is connection strings, but there’s a catch. You may have set the value in the configuration, but the value either is to a non-existent resource or the resource is inaccessible.&lt;/p&gt;

&lt;p&gt;In this short post, we’ll write an extension method and a class that will allow you to test your database connection on startup and fail the application if you can’t connect.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-initial-host-configuration&quot;&gt;The Initial Host Configuration&lt;/h2&gt;

&lt;p&gt;Let’s look at the final solution and work our way backward. We have our application host, and we register a connection string validator. Our validation will get the connection string, determine the provider, and attempt a connection. If successful, the app starts. If unsuccessful, the app exits.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Data.Common;
using Microsoft.Data.SqlClient;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WorkerServiceDatabase;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =&amp;gt;
    {
        services
            .ValidateConnectionStrings()
            .ValidateOnStart();
        
        services.AddHostedService&amp;lt;Worker&amp;gt;();
    })
    .Build();

host.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat, let’s see what challenges we have to overcome.&lt;/p&gt;

&lt;h2 id=&quot;the-connectionstring-configuration&quot;&gt;The ConnectionString Configuration&lt;/h2&gt;

&lt;p&gt;.NET allows you to bind a configuration to a strongly-typed object, but in the case of &lt;code&gt;ConnectionStrings&lt;/code&gt;, that’s a well-known JSON section. So how do we accomplish that? Well, let’s have a look at our working configuration.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Information&quot;
    }
  },
  &quot;ConnectionStrings&quot;: {
      &quot;Sqlite&quot;: &quot;Data Source=database.db&quot;,
      &quot;SqlServer&quot;: &quot;Data Source=localhost,11433;Initial Catalog=Northwind;User Id=sa;Password=Pass123!;Encrypt=false&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ConnectionStrings&lt;/code&gt; looks like a JSON Dictionary, so we can bind to a class that inherits from &lt;code&gt;Dictionary&amp;lt;string,string&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class ConnectionStrings
    : Dictionary&amp;lt;string,string&amp;gt;
{}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome, but there’s a problem. None of our connection strings declare the database provider. So here’s the first decision you’ll want to make for your use case: “How do you map connection string names to their database providers?”&lt;/p&gt;

&lt;p&gt;My approach to this issue was explicitly mapping the keys to a database provider in my &lt;code&gt;ConnectionStrings&lt;/code&gt; constructor.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class ConnectionStrings
    : Dictionary&amp;lt;string,string&amp;gt;
{
    public ConnectionStrings()
    {
        // these are the key names
        DbProviderFactories.RegisterFactory(&quot;Sqlite&quot;, SqliteFactory.Instance);
        DbProviderFactories.RegisterFactory(&quot;SqlServer&quot;, SqlClientFactory.Instance);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These database factories come from the NuGet packages of &lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt; and &lt;code&gt;Microsoft.Data.Sqlite&lt;/code&gt;. You’ll need to add other database factories for providers like PostgreSQL, MySQL, or Oracle.&lt;/p&gt;

&lt;p&gt;Next, let’s write our &lt;code&gt;Validate&lt;/code&gt; method. This method will create a new connection using our connection strings and then attempt to open a connection to the database.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class ConnectionStrings
    : Dictionary&amp;lt;string,string&amp;gt;
{
    public ConnectionStrings()
    {
        // these are the key names
        DbProviderFactories.RegisterFactory(&quot;Sqlite&quot;, SqliteFactory.Instance);
        DbProviderFactories.RegisterFactory(&quot;SqlServer&quot;, SqlClientFactory.Instance);
    }
    
    public bool Validate()
    {
        // can&apos;t inject logger :(
        var logger = LoggerFactory
            .Create(cfg =&amp;gt; cfg.AddConsole().AddDebug())
            .CreateLogger(&quot;ConnectionStrings&quot;);
        
        List&amp;lt;Exception&amp;gt; errors = new();
        foreach (var (key, connectionString) in this)
        {
            try
            {
                var factory = DbProviderFactories.GetFactory(key);
                using var connection = factory.CreateConnection();
                if (connection is null) {
                    throw new Exception($&quot;\&quot;{key}\&quot; did not have a valid database provider registered&quot;);
                }

                connection.ConnectionString = connectionString;
                connection.Open();
            }
            catch (Exception e)
            {
                var message = $&quot;Could not connect to \&quot;{key}\&quot;.&quot;;
                logger.LogError(message);
                errors.Add(new Exception(message, e));
            }
        }

        return errors.IsNullOrEmpty();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The validate method loops over the values in our &lt;code&gt;ConnectionString&lt;/code&gt; section, finding the &lt;code&gt;DbProviderFactory&lt;/code&gt; and creating a connection.&lt;/p&gt;

&lt;p&gt;I had to create a new logger factory so you could see the failed connection, but you could remove that if you want an all-or-nothing approach.&lt;/p&gt;

&lt;p&gt;We have our class; now let’s wire it up.&lt;/p&gt;

&lt;h2 id=&quot;the-connectionstring-validation-method&quot;&gt;The ConnectionString Validation Method&lt;/h2&gt;

&lt;p&gt;This section is pretty straightforward, we’ll write an extension method to bind our &lt;code&gt;ConnectionStrings&lt;/code&gt; configuration section to our &lt;code&gt;ConnectionStrings&lt;/code&gt; class and call the validate method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public static class ConnectionStringExtensions
{
    public static OptionsBuilder&amp;lt;ConnectionStrings&amp;gt; 
        ValidateConnectionStrings(this IServiceCollection services)
    {
        return services
            .AddOptions&amp;lt;ConnectionStrings&amp;gt;()
            .BindConfiguration(&quot;ConnectionStrings&quot;)
            .Validate(c =&amp;gt; c.Validate(), &quot;Could not connect to 1 or more databases.&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Easy peasy.&lt;/p&gt;

&lt;h2 id=&quot;the-complete-solution&quot;&gt;The Complete Solution&lt;/h2&gt;

&lt;p&gt;So how does this all look in one file? Where here it is.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Data.Common;
using Microsoft.Data.SqlClient;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WorkerServiceDatabase;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =&amp;gt;
    {
        services 
            // validate connection strings
            .ValidateConnectionStrings()
            .ValidateOnStart();
        
        services.AddHostedService&amp;lt;Worker&amp;gt;();
    })
    .Build();

host.Run();

public static class ConnectionStringExtensions
{
    public static OptionsBuilder&amp;lt;ConnectionStrings&amp;gt; 
        ValidateConnectionStrings(this IServiceCollection services)
    {
        return services
            .AddOptions&amp;lt;ConnectionStrings&amp;gt;()
            .BindConfiguration(&quot;ConnectionStrings&quot;)
            .Validate(c =&amp;gt; c.Validate(), &quot;Could not connect to 1 or more databases.&quot;);
    }
}

public class ConnectionStrings
    : Dictionary&amp;lt;string,string&amp;gt;
{
    public ConnectionStrings()
    {
        // these are the key names
        DbProviderFactories.RegisterFactory(&quot;Sqlite&quot;, SqliteFactory.Instance);
        DbProviderFactories.RegisterFactory(&quot;SqlServer&quot;, SqlClientFactory.Instance);
    }
    
    public bool Validate()
    {
        // can&apos;t inject logger :(
        var logger = LoggerFactory
            .Create(cfg =&amp;gt; cfg.AddConsole().AddDebug())
            .CreateLogger(&quot;ConnectionStrings&quot;);
        
        List&amp;lt;Exception&amp;gt; errors = new();
        foreach (var (key, connectionString) in this)
        {
            try
            {
                var factory = DbProviderFactories.GetFactory(key);
                using var connection = factory.CreateConnection();
                if (connection is null) {
                    throw new Exception($&quot;\&quot;{key}\&quot; did not have a valid database provider registered&quot;);
                }

                connection.ConnectionString = connectionString;
                connection.Open();
            }
            catch (Exception e)
            {
                var message = $&quot;Could not connect to \&quot;{key}\&quot;.&quot;;
                logger.LogError(message);
                errors.Add(new Exception(message, e));
            }
        }

        return errors.IsNullOrEmpty();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you have it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important. The validation process in .NET uses a &lt;code&gt;ValidationHostedService&lt;/code&gt;, so it’s important that if you have any hosted service that relies on your configuration, then you should register them after your validation runs. If you don’t you’ll have your hosted service start before validation is completed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Using .NET configuration extension points, we can validate the most critical resources. For example, using the &lt;code&gt;DbProviderFactories&lt;/code&gt; class, we can register and support many database providers. However, you must make a design choice, as the &lt;code&gt;ConnectionStrings&lt;/code&gt; section in the configuration doesn’t allow the provider to be set. Ultimately, my approach wasn’t too bad, but it could be better. Also, I found that the &lt;code&gt;ConnectionStrings&lt;/code&gt; class instance must have a parameterless constructor and could not inject an instance of &lt;code&gt;ILogger&lt;/code&gt;, which is why I created my own. If you are fine with a “pass/fail” approach, feel free to exclude the logger, which might lead to frustrating debugging to determine which connection string failed.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and I hope you enjoyed this post.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/validating-connection-strings-on-dotnet-startup</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/validating-connection-strings-on-dotnet-startup</guid>
        
        <category>aspnet,</category>
        
        <category>dotnet</category>
        
        
      </item>
    
      <item>
        <title>Speed Up ASP.NET Core JSON APIs with Source Generators</title>
        <description>&lt;p&gt;Building applications is a virtuous circle of learning about problems, finding solutions, and optimizing. I find optimizing an application the most fun, as it can help you squeeze performance out from surprising places.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how you can use the latest JSON source generators shipped in .NET 6 to improve your JSON API performance and increase your response throughput.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Like many source generators in .NET, the &lt;strong&gt;System.Text.Json&lt;/strong&gt; source generator enhances an existing partial class with essential elements required for serialization. Those elements include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;code&gt;JsonTypeInfo&amp;lt;T&amp;gt;&lt;/code&gt; for each serializable entity in your object graph.&lt;/li&gt;
  &lt;li&gt;A default instance of a &lt;code&gt;JsonSerializerContext&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;JsonSerialiazerOptions&lt;/code&gt; for formatting JSON on serialization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t worry; it’s not as complex as it sounds. Let’s first start with our entity.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public record Person(
    string Name,
    bool IsCool = true,
    Person? Friend = null
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We want to optimize the serialization of this record. Since we know structurally what this entity looks like, we can create a rigid and streamlined serializer, which should improve overall performance. Therefore, we first define a &lt;code&gt;PersonSerializationContext&lt;/code&gt; derived from &lt;code&gt;JsonSerialzerContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[JsonSourceGenerationOptions(
    WriteIndented = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(Person))]
public partial class PersonSerializationContext 
    : JsonSerializerContext {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Essential elements of this definition include:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;partial&lt;/code&gt; keyword. The source generator will create the implementation of our class for us.
The &lt;code&gt;JsonSourceGenerationOptions&lt;/code&gt; attribute allows us to customize serialization with the correct casing, null handling, and much more. Don’t forget this if you have specific serialization needs.
The &lt;code&gt;JsonSerializable&lt;/code&gt; attribute for non-standard types during serialization. Each attribute of this kind will produce a &lt;code&gt;JsonTypeInfo&lt;/code&gt; property on our context class.&lt;/p&gt;

&lt;p&gt;Cool, let’s see how we can use our new &lt;code&gt;PersonSerializationContext&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Json;
using System.Text.Json.Serialization;

var person = new Person(&quot;Khalid&quot;, Friend: new(&quot;Maarten&quot;));

var json =
    JsonSerializer.Serialize(
        person,
        PersonSerializationContext.Default.Person);

Console.WriteLine(json);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running our application, we see the desired output. You’ll note that the result uses camel casing and that serialization did not output null values.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;Khalid&quot;,
  &quot;isCool&quot;: true,
  &quot;friend&quot;: {
    &quot;name&quot;: &quot;Maarten&quot;,
    &quot;isCool&quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, how do you take advantage of your new &lt;code&gt;PersonSerializationContext&lt;/code&gt; in an ASP.NET Core application? Well, it’s pretty straightforward.&lt;/p&gt;

&lt;p&gt;Inside of an existing Minimal APIs endpoint, you’ll need to use the &lt;code&gt;Results.Json&lt;/code&gt; method and pass it your generated &lt;code&gt;Options&lt;/code&gt; found on the &lt;code&gt;Default&lt;/code&gt; property.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Hello World!&quot;);

app.MapGet(&quot;person&quot;, () =&amp;gt; 
    Results.Json(
        new Person(&quot;Khalid&quot;, Friend: new(&quot;Maarten&quot;)), 
        PersonSerializationContext.Default.Options));

app.Run();

[JsonSourceGenerationOptions(
    WriteIndented = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(Person))]
public partial class PersonSerializationContext 
    : JsonSerializerContext {}

public record Person(
    string Name,
    bool IsCool = true,
    Person? Friend = null
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running the ASP.NET Core application and hitting the endpoint produces the expected results, the same as we saw before in our console application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;// 20230210114342
// http://localhost:5115/person

{
  &quot;name&quot;: &quot;Khalid&quot;,
  &quot;isCool&quot;: true,
  &quot;friend&quot;: {
    &quot;name&quot;: &quot;Maarten&quot;,
    &quot;isCool&quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While hearing the phrase “source generators” might be scary at first, this optimization can improve your APIs’ performance with minimal effort. A few lines of code and some refactoring, and you’re off to the races.&lt;/p&gt;

&lt;p&gt;If you’re going to use this technique, I recommend finding your application’s hottest paths and starting there. Then measure to see what kind of serialization overhead you’ve reduced.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts with your colleagues. If you have any questions, please feel free to reach out.&lt;/p&gt;
</description>
        <pubDate>Tue, 28 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/speed-up-aspnet-core-json-apis-with-source-generators</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/speed-up-aspnet-core-json-apis-with-source-generators</guid>
        
        <category>aspnet,</category>
        
        <category>json</category>
        
        
      </item>
    
      <item>
        <title>Combining 11ty Static Site Generator with ASP.NET Core</title>
        <description>&lt;p&gt;I love many things about static site generators, but I mainly enjoy the challenge of building a fast user experience, given development time constraints. The constraints force me to be mindful of every new feature I add, the content I want to present, and the resources I use to accomplish all my goals. I believe that most, if not all, experiences on the web could benefit from some element of static site generation. While that may or may not be true, I believe in the inverse statement. Some static sites could benefit from a dynamic backend to provide unique and personalized experiences.&lt;/p&gt;

&lt;p&gt;This post will explore adding 11ty, one of my favorite static site generator tools, to an ASP.NET Core application. We’ll see how this approach will allow us to build out static content while taking advantage of a dynamic and programmable hosting platform. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;setting-up-an-aspnet-core-web-project-for-11ty&quot;&gt;Setting up an ASP.NET Core Web Project for 11ty&lt;/h2&gt;

&lt;p&gt;Let’s start with an ASP.NET Core &lt;strong&gt;Empty&lt;/strong&gt; template, a barebones solution. We’ll be adding a few files and folders. First, let’s create a new &lt;code&gt;site&lt;/code&gt; folder. This directory will hold all our static content that 11ty will process into static files.&lt;/p&gt;

&lt;p&gt;The next step is creating a &lt;code&gt;package.json&lt;/code&gt; file to manage our NPM packages. Finally, we’ll create a build script to process our static content. Here are the contents of &lt;code&gt;/site/package.json&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;site&quot;,
  &quot;private&quot;: true,
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;node node_modules/.bin/eleventy&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@11ty/eleventy&quot;: &quot;^2.0.0-beta.3&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here, we can run &lt;code&gt;npm install&lt;/code&gt; to install all the development dependencies. Feel free to add any other NPM packages for your static site. 11ty has a lot of great options too, so I imagine many folks will.&lt;/p&gt;

&lt;p&gt;The next step is to add an &lt;code&gt;eleventy.config.js&lt;/code&gt; file, which will help the 11ty process copy assets to our destination of &lt;code&gt;wwwroot&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;module.exports = function (eleventyConfig) {
    // copy images, css, and js from /assets
    eleventyConfig.addPassthroughCopy(&quot;./assets&quot;)
    return {
        dir: {
            passthroughFileCopy: true,
            // write to aspnet.core output directory
            output: &quot;../wwwroot&quot;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re checking this project into source control, as you should, you may want to ignore the contents of &lt;code&gt;wwwroot&lt;/code&gt; as they are artifacts of the build process and will likely be changing regularly.&lt;/p&gt;

&lt;p&gt;Next, let’s add some content and templates for 11ty to process. First, create a new folder under &lt;code&gt;site&lt;/code&gt; called &lt;code&gt;_includes&lt;/code&gt;. Once you’ve made the folder, add the following &lt;code&gt;layout.html&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;{{ title }}&amp;lt;/title&amp;gt;
    &amp;lt;meta name=&quot;Description&quot; content=&quot;{{ description }}&quot; /&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;/assets/styles.css&quot; /&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div class=&quot;content&quot;&amp;gt;{{ content }}&amp;lt;/div&amp;gt;
&amp;lt;script src=&quot;/assets/script.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, create an &lt;code&gt;assets&lt;/code&gt; folder under &lt;code&gt;site&lt;/code&gt; and add two files, &lt;code&gt;script.js&lt;/code&gt; and &lt;code&gt;styles.css&lt;/code&gt;. We’ve referenced these files in the layout, but we need some content. Here is the content for our JavaScript file. The stylesheet content can be empty for now.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;;(function () {
    console.log(&quot;Hello there!&quot;)

    fetch(&apos;/api/current-time&apos;)
        .then((response) =&amp;gt; response.json())
        .then((data) =&amp;gt; {
            const el =document.getElementById(&apos;target&apos;);
            el.innerText =`the current date time is ${data.datetime}`; 
        });
})()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Spoiler, we’ll be implementing an ASP.NET Core API endpoint and calling it from our static files.&lt;/p&gt;

&lt;p&gt;Finally, let’s add an &lt;code&gt;index.md&lt;/code&gt; file. 11ty allows you to write your content in multiple templating languages, with my favorite being plain-old markdown.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;
---
title: &quot;Hello 11ty&quot;
layout: layout.html
description: Hosting 11ty on ASP.NET Core
---

# This Is Eleventy Served from ASP.NET Core

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

&amp;lt;h1 id=&quot;target&quot;&amp;gt;Loading...&amp;lt;/h1&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s get back to the world of .NET. The following section will set up our build process and the ASP.NET Core pipeline.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-aspnet-core-to-build-11ty&quot;&gt;Setting Up ASP.NET Core to build 11ty&lt;/h2&gt;

&lt;p&gt;First, we need MSBuild to execute our NPM &lt;code&gt;build&lt;/code&gt; script. That’s as straightforward as adding a &lt;code&gt;Target&lt;/code&gt; to the &lt;code&gt;.csrpoj&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk.Web&quot;&amp;gt;

    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;TargetFramework&amp;gt;net7.0&amp;lt;/TargetFramework&amp;gt;
        &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
        &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

    &amp;lt;ItemGroup&amp;gt;
      &amp;lt;Folder Include=&quot;wwwroot&quot; /&amp;gt;
    &amp;lt;/ItemGroup&amp;gt;

    &amp;lt;Target Name=&quot;11ty&quot; BeforeTargets=&quot;Build&quot;&amp;gt;
        &amp;lt;Exec Command=&quot;npm install &amp;amp;amp;&amp;amp;amp; npm run build&quot; WorkingDirectory=&quot;site&quot; /&amp;gt;
    &amp;lt;/Target&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;It’s important to set the &lt;code&gt;WorkingDirectory&lt;/code&gt; attribute to &lt;code&gt;site&lt;/code&gt;, or else NPM will not find the script.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next phase in our process is to configure our ASP.NET Core pipeline. We only need two pieces of middleware: &lt;code&gt;DefaultFilesMiddleware&lt;/code&gt; and &lt;code&gt;StaticFilesMiddleware&lt;/code&gt;. We’ll also take this opportunity to add our ASP.NET Core Minimal API endpoint.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseDefaultFiles();
app.UseStaticFiles();

app.MapGet(&quot;/api/current-time&quot;, () =&amp;gt; new
{
    datetime = DateTime.Now
});

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that’s it! You now have a working &lt;strong&gt;&lt;a href=&quot;https://github.com/khalidabuhakmeh/EleventyCore&quot;&gt;11ty and ASP.NET Core web project&lt;/a&gt;&lt;/strong&gt;. I’ve uploaded it to my GitHub repository if you’d like a quicker starting point.**&lt;/p&gt;

&lt;p&gt;As always, thanks for reading, and I hope this helps you. If you enjoyed this post, please share it with friends and colleagues.&lt;/p&gt;

</description>
        <pubDate>Tue, 21 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/combining-11ty-static-site-generator-with-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/combining-11ty-static-site-generator-with-aspnet-core</guid>
        
        <category>aspnet,</category>
        
        <category>static</category>
        
        
      </item>
    
      <item>
        <title>Generating Bogus HTTP Endpoints with ASP.NET Core Minimal APIs</title>
        <description>&lt;p&gt;As a developer advocate, I find myself writing a lot of demos for folks around .NET and, specifically, the ASP.NET Core parts of the stack. Unfortunately, writing repetitive boilerplate can make me feel like &lt;a href=&quot;https://www.imdb.com/title/tt0081505/&quot;&gt;Jack Torrence from The Shining movie&lt;/a&gt;: &lt;strong&gt;&lt;em&gt;“All work and no play makes &lt;a href=&quot;https://mastodon.social/@khalidabuhakmeh&quot;&gt;Khalid&lt;/a&gt; a dull boy.”&lt;/em&gt;&lt;/strong&gt; Nobody likes the drudgery of repeating yourself, nobody! So, given my situation, I thought I’d chase this problem down in a maze with a metaphorical axe. So, what am I trying to accomplish?&lt;/p&gt;

&lt;p&gt;What if I could take an existing C# model and build a low-ceremony set of test endpoints that follow standard HTTP semantics, and how would I accomplish that?&lt;/p&gt;

&lt;p&gt;In this article, you’ll see how I built a single registration for test endpoints that you can use to prototype UIs quickly for frameworks like React, Blazor, Angular, or vanilla JavaScript. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-basics-of-an-http-api&quot;&gt;The Basics of an HTTP API&lt;/h2&gt;

&lt;p&gt;For folks unfamiliar with building an HTTP API, the HTTP semantics are essential to the implementation on the server. Elements of an HTTP request include the method, headers, path, query-string values, and the optional payload. Without all these elements, your HTTP API limits how and what your user can send to your endpoint.&lt;/p&gt;

&lt;p&gt;On the flip side, you have the HTTP Request, which has headers, payload, and status code elements. The server uses these values to tell a client what occurred on the server via a status code and what the client can expect regarding the type of payload.&lt;/p&gt;

&lt;p&gt;In addition to HTTP semantics, I typically center the creation of HTTP APIs around a “resource”. A resource is a logical entity that a user reads and writes through requests and receives in response payloads. In my experience, an API resource can be something like a &lt;strong&gt;Person&lt;/strong&gt;, &lt;strong&gt;Quotes&lt;/strong&gt;, and so on.&lt;/p&gt;

&lt;p&gt;I’ve found that building my HTTP APIs around HTTP semantics and resources makes the process of reasoning and maintaining a project simpler in the long run.&lt;/p&gt;

&lt;h2 id=&quot;the-aspnet-core-registration&quot;&gt;The ASP.NET Core Registration&lt;/h2&gt;

&lt;p&gt;We’ll start with the user experience I’m aiming for and then look at how to implement the code behind the endpoint registration. I aim to have a low-ceremony registration to add essential create, read, update, and delete endpoints. The endpoints will also adhere to standard HTTP semantics. Additionally, I want persistence between requests, so the user can create or update a new resource and then retrieve it using the identity. First, let’s look at the &lt;code&gt;Program.cs&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using BogusEndpoints;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Hello World!&quot;);

app.MapAutoBogusEndpoint&amp;lt;Person&amp;gt;(&quot;/people&quot;, rules =&amp;gt;
{
    rules.RuleFor(p =&amp;gt; p.Id, f =&amp;gt; f.IndexGlobal + 1);
    rules.RuleFor(p =&amp;gt; p.FullName, f =&amp;gt; f.Name.FullName());
});

app.Run();

public record Person(int Id, string FullName)
{
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public Dog Dog { get; set; }
}

public record Dog(string Name);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice the call to &lt;code&gt;MapAutoBogusEndpoint&lt;/code&gt; allows the user to set a root path and the ability to configure the kind of data for the resource. Any property the user does not set will get random data based on the property type. For example, let’s make an HTTP call to the Index endpoint to retrieve a list of &lt;code&gt;Person&lt;/code&gt; resources, limiting the result to&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;GET http://localhost:5208/people?pageSize=1

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Thu, 02 Feb 2023 16:20:23 GMT
Server: Kestrel
Transfer-Encoding: chunked

{
  &quot;results&quot;: [
    {
      &quot;id&quot;: 1,
      &quot;fullName&quot;: &quot;Ofelia Vandervort&quot;,
      &quot;createdAt&quot;: &quot;2023-02-02T01:32:03.1170216-05:00&quot;,
      &quot;dog&quot;: {
        &quot;name&quot;: &quot;Toys &amp;amp; Health&quot;
      }
    }
  ],
  &quot;page&quot;: 1,
  &quot;pageSize&quot;: 1,
  &quot;totalItemCount&quot;: 1000
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s pretty cool, right?! Other calls like creating, updating, and deleting also work.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;PUT http://localhost:5208/people/1
Content-Type: application/json

{
  &quot;id&quot;: 1,
  &quot;fullName&quot;: &quot;Khalid Abuhakmeh&quot;,
  &quot;createdAt&quot;: &quot;2023-02-02T01:32:03.1170216-05:00&quot;,
  &quot;dog&quot;: {
    &quot;name&quot;: &quot;Toys &amp;amp; Health&quot;
  }
}
###

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Thu, 02 Feb 2023 16:28:34 GMT
Server: Kestrel
Transfer-Encoding: chunked

{
  &quot;id&quot;: 1,
  &quot;fullName&quot;: &quot;Khalid Abuhakmeh&quot;,
  &quot;createdAt&quot;: &quot;2023-02-02T01:32:03.1170216-05:00&quot;,
  &quot;dog&quot;: {
    &quot;name&quot;: &quot;Toys &amp;amp; Health&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I make the best effort to assign the identifiers if an identifier needs to be incremented or generated. That said, in most cases, an HTTP API will expect that the user passes most data representing the state.&lt;/p&gt;

&lt;p&gt;So how is this all done?&lt;/p&gt;

&lt;h2 id=&quot;generating-boilerplate-prototype-endpoints&quot;&gt;Generating Boilerplate Prototype Endpoints&lt;/h2&gt;

&lt;p&gt;I accomplish most of the work using the NuGet library &lt;strong&gt;&lt;a href=&quot;https://www.nuget.org/packages/AutoBogus&quot;&gt;AutoBogus&lt;/a&gt;&lt;/strong&gt;. The configuration action allows you to configure each property accordingly when registering the endpoint. I’ll paste most of the code here.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using AutoBogus;
using Microsoft.AspNetCore.Mvc;
using X.PagedList;

namespace BogusEndpoints;

public static class BogusEndpointsExtensions
{
    public static RouteGroupBuilder MapAutoBogusEndpoint&amp;lt;TResource&amp;gt;(
        this WebApplication app,
        PathString prefix,
        Action&amp;lt;AutoFaker&amp;lt;TResource&amp;gt;&amp;gt;? builder = null
    ) where TResource : class
    {
        var group = app.MapGroup(prefix)
            .WithGroupName($&quot;{typeof(TResource).FullName}_Bogus&quot;);

        var faker = new AutoFaker&amp;lt;TResource&amp;gt;();
        builder?.Invoke(faker);

        // generate a working collection
        // will allocate objects in memory
        var db = faker.Generate(1000);

        // INDEX
        group.MapGet(&quot;&quot;, (int? pageSize, int? page) =&amp;gt;
            {
                var result = db
                    .ToPagedList(
                        page.GetValueOrDefault(1),
                        pageSize.GetValueOrDefault(10));

                return new
                {
                    results = result,
                    page = result.PageNumber,
                    pageSize = result.PageSize,
                    totalItemCount = result.TotalItemCount
                };
            })
        .WithName($&quot;{typeof(TResource).FullName}_Bogus+List&quot;);

        // SHOW
        group.MapGet(&quot;{id}&quot;, (string id) =&amp;gt;
        {
            var result = db.FirstOrDefault(t =&amp;gt; FindById(t, id));
            return result != null ? Results.Ok(result) : Results.NotFound();
        })
        .WithName($&quot;{typeof(TResource).FullName}_Bogus+Show&quot;);

        // POST
        group.MapPost(&quot;&quot;, (TResource item) =&amp;gt;
        {
            try
            {
                dynamic generated = faker.Generate(1)[0];
                SetId(item, generated.Id);
                db.Add(item);
                return Results.CreatedAtRoute(
                    $&quot;{typeof(TResource).FullName}_Bogus+Show&quot;,
                    new { id = generated.Id },
                    item
                );
            }
            catch
            {
                return Results.Ok(item);
            }
        }).WithName($&quot;{typeof(TResource).FullName}_Bogus+Create&quot;);

        // PUT
        group.MapPut(&quot;{id}&quot;, (string id, [FromBody] TResource item) =&amp;gt;
        {
            var index = db.FindIndex(t =&amp;gt; FindById(t, id));
            if (index &amp;lt; 0) return Results.NotFound();
            SetId(id, item);
            db[index] = item;
            return Results.Ok(item);
        }).WithName($&quot;{typeof(TResource).FullName}_Bogus+Update&quot;);

        // DELETE
        group.MapDelete(&quot;{id}&quot;, (string id) =&amp;gt;
        {
            db.RemoveAll(t =&amp;gt; FindById(t, id));
            return Results.Accepted();
        })
        .WithName($&quot;{typeof(TResource).FullName}_Bogus+Delete&quot;);
        
        return group;
    }

    private static bool FindById&amp;lt;TResource&amp;gt;(TResource target, object? id)
    {
        if (id is null)
            return false;

        var type = typeof(TResource);
        var identifier = type
            .GetProperties()
            .FirstOrDefault(p =&amp;gt; p.Name == &quot;Id&quot;);

        if (identifier == null)
            return false;

        object? converted = Convert.ChangeType(id, identifier.PropertyType);
        if (converted == null) return false;
        var value = identifier.GetValue(target);
        var result = converted.Equals(value);
        return result;
    }
    
    private static void SetId&amp;lt;TResource&amp;gt;(TResource target, object? id)
    {
        if (id is null)
            return;

        var type = typeof(TResource);
        var identifier = type
            .GetProperties()
            .FirstOrDefault(p =&amp;gt; p.Name == &quot;Id&quot;);

        if (identifier == null)
            return;

        object? converted = Convert.ChangeType(id, identifier.PropertyType);
        if (converted == null) return;
        identifier.SetValue(target, converted);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All you need to do is create your resource types, such as &lt;code&gt;Person,&lt;/code&gt; and you’ll get all the necessary machinery for an HTTP API. But there’s still something missing. What about validation results?&lt;/p&gt;

&lt;h2 id=&quot;adding-validation-to-bogus-endpoints&quot;&gt;Adding Validation to Bogus Endpoints&lt;/h2&gt;

&lt;p&gt;I made a calculated effort to return the &lt;code&gt;RouteGroupBuilder&lt;/code&gt; from each registration call, allowing you to add any endpoint filter to a group. Exposing this object instance makes it trivial to add &lt;strong&gt;FluentValidation&lt;/strong&gt; as an endpoint filter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using BogusEndpoints;
using FluentValidation;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddValidatorsFromAssemblyContaining&amp;lt;Program&amp;gt;();

var app = builder.Build();

app.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Hello World!&quot;);

app.MapAutoBogusEndpoint&amp;lt;Person&amp;gt;(&quot;/people&quot;, rules =&amp;gt;
{
    rules.RuleFor(p =&amp;gt; p.Id, f =&amp;gt; f.IndexGlobal + 1);
    rules.RuleFor(p =&amp;gt; p.FullName, f =&amp;gt; f.Name.FullName());
})
.AddEndpointFilter&amp;lt;PersonValidationFilter&amp;gt;();

app.Run();

public record Person(int Id, string FullName)
{
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public Dog Dog { get; set; }
}

public record Dog(string Name);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We tie the validator specifically to the resource of &lt;code&gt;Person&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using FluentValidation;

public class PersonValidationFilter : IEndpointFilter
{
    public async ValueTask&amp;lt;object?&amp;gt; InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
    {
        var validator = context.HttpContext.RequestServices.GetRequiredService&amp;lt;PersonValidator&amp;gt;();
        foreach (var arg in context.Arguments)
        {
            if (arg is not Person person) continue;
            var result = await validator.ValidateAsync(person);
            if (result.IsValid) continue;
            var errors = result.Errors
                .GroupBy(e =&amp;gt; e.PropertyName)
                .ToDictionary(
                    g =&amp;gt; g.Key, 
                    g =&amp;gt; g.Select(e =&amp;gt; e.ErrorMessage).ToArray()
                );

            return Results.ValidationProblem(errors);
        }

        return await next(context);
    }
}

public class PersonValidator : AbstractValidator&amp;lt;Person&amp;gt;
{
    public PersonValidator()
    {
        RuleFor(m =&amp;gt; m.FullName).NotEmpty();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Any call to an endpoint not meeting your validation criteria will return an appropriate problem details response and status code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;POST http://localhost:5208/people

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Date: Thu, 02 Feb 2023 16:56:57 GMT
Server: Kestrel
Transfer-Encoding: chunked

{
  &quot;type&quot;: &quot;https://tools.ietf.org/html/rfc7231#section-6.5.1&quot;,
  &quot;title&quot;: &quot;One or more validation errors occurred.&quot;,
  &quot;status&quot;: 400,
  &quot;errors&quot;: {
    &quot;FullName&quot;: [
      &quot;&apos;Full Name&apos; must not be empty.&quot;
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool!&lt;/p&gt;

&lt;h2 id=&quot;other-ideas-around-bogus-endpoints&quot;&gt;Other Ideas around Bogus Endpoints&lt;/h2&gt;

&lt;p&gt;This current implementation relies on runtime generation, which is ok for testing purposes, but there are a lot of potential pitfalls, primarily around identifiers. Using source code generators, you could make the endpoints rely less on reflection and more on the design-time types of the resource models. In addition, the use of source generators could lead to fewer edge case bugs.&lt;/p&gt;

&lt;p&gt;.NET Community member &lt;strong&gt;João Antunes&lt;/strong&gt;  has &lt;a href=&quot;https://blog.codingmilitia.com/2023/01/31/mapping-aspnet-core-minimal-api-endpoints-with-csharp-source-generators/&quot;&gt;an excellent blog post detailing registering Minimal API endpoints using source code generators&lt;/a&gt;. I could see someone adapting both our ideas into something useful for the community at large.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you’ve ever found yourself in a situation where you needed some test endpoints to match your models but were more focused on the UI/UX rather than the implementation, this solution might be for you. The approach in this post could use some optimizations and edge case handling, but I’ll leave it up to you to work through those.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading, and I hope you enjoyed this post. If you did, please feel to share it with friends and colleagues.&lt;/p&gt;
</description>
        <pubDate>Tue, 14 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/generating-bogus-http-endpoints-with-aspnet-core-minimal-apis</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/generating-bogus-http-endpoints-with-aspnet-core-minimal-apis</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>How to use Entity Framework Core in ASP.NET Core</title>
        <description>&lt;p&gt;Moving from one ecosystem to another can be challenging, especially when unfamiliar with the technology stack and available tools. So I wrote this post for anyone coming to ASP.NET Core from another ecosystem or .NET developers who might be dabbling with web development for the first time. Knowing where all the bits and bobs are in a new environment can be overwhelming, and I’m here to help.&lt;/p&gt;

&lt;p&gt;As you read through the post, we’ll create a new ASP.NET Core project, integrate a data access library called Entity Framework Core 7, and discuss the steps you need to take toward a straightforward solution. Like all solutions, I developed this guidance from my first-hand experience.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Please do so if you’d like to experiment with your choices at any point in this tutorial. This guide is a jumping-off point so you can succeed. This blog post assumes you have &lt;a href=&quot;https://dot.net&quot;&gt;.NET installed&lt;/a&gt; and some kind of editor or tooling. I recommend &lt;a href=&quot;https://jetbrains.com/rider&quot;&gt;JetBrains Rider&lt;/a&gt; but this tutorial should work with Visual Studio and Visual Studio Code.&lt;/p&gt;

&lt;p&gt;Let’s go ahead and get started.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-new-aspnet-core-web-project&quot;&gt;Creating a New ASP.NET Core Web Project&lt;/h2&gt;

&lt;p&gt;Before we get started, you’ll need to create a new ASP.NET Core solution. Creating a new .NET solution can typically be done in one of two ways: Command-line tooling or through your favorite IDE (I prefer JetBrains Rider).&lt;/p&gt;

&lt;p&gt;For this guide, I’ll show you how to create a new &lt;strong&gt;Razor Pages&lt;/strong&gt; web project using the command line. First, in a new terminal, type the following command.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;dotnet new webapp -o WebApplication
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The command will create a web project ready for development. &lt;strong&gt;Note: This template is available in most IDEs and will create an additional solution file with your project in a nested folder when selected.&lt;/strong&gt;  A solution is a typical structure for most .NET applications, as you may have more than one project per solution.&lt;/p&gt;

&lt;p&gt;You’re ready to start adding some of our necessary dependencies from here.&lt;/p&gt;

&lt;h2 id=&quot;tools-and-nuget-dependencies&quot;&gt;Tools and NuGet Dependencies&lt;/h2&gt;

&lt;p&gt;We’ll start by installing a tool manifest in our solution directory. The tool manifest keeps track of all command-line tooling installed for the current solution, and many of EF Core’s management feature set exists in the &lt;code&gt;dotnet-ef&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;Type the following command from the root folder of your solution.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;dotnet new tool-manifest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The command will create a &lt;code&gt;.config&lt;/code&gt; folder with a &lt;code&gt;dotnet-tool.json&lt;/code&gt; file. It’s not necessary to look at it. Just know it’s a manifest of all the tools installed for your local development needs.&lt;/p&gt;

&lt;p&gt;Next, you’ll need to install the EF Core 7 tooling with the following command.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;dotnet tool install dotnet-ef
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let’s move on to installing our EF Core 7 dependencies.&lt;/p&gt;

&lt;p&gt;You’ll need to install two specific packages in your web application project.&lt;/p&gt;

&lt;p&gt;The first package is your EF Core database provider package, and you can choose from Microsoft SQL Server, PostgreSQL, MySQL, or other providers. In this case, I decided to use SQLite because it’s file-based and gets the point across.&lt;/p&gt;

&lt;p&gt;The second is EF Core’s &lt;strong&gt;Design&lt;/strong&gt; package, which allows you to generate database migrations. These migrations help keep your database schema compatible with your C# models.&lt;/p&gt;

&lt;p&gt;Here’s my &lt;code&gt;.csproj&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&quot;Microsoft.NET.Sdk.Web&quot;&amp;gt;

    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;TargetFramework&amp;gt;net7.0&amp;lt;/TargetFramework&amp;gt;
        &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
        &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

    &amp;lt;ItemGroup&amp;gt;
      &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore.Design&quot; Version=&quot;7.0.2&quot;&amp;gt;
        &amp;lt;PrivateAssets&amp;gt;all&amp;lt;/PrivateAssets&amp;gt;
        &amp;lt;IncludeAssets&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/IncludeAssets&amp;gt;
      &amp;lt;/PackageReference&amp;gt;
      &amp;lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore.Sqlite&quot; Version=&quot;7.0.2&quot; /&amp;gt;
    &amp;lt;/ItemGroup&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;NuGet will install all other EF Core packages transitively from these two packages. Our web application is now ready for some code.&lt;/p&gt;

&lt;h2 id=&quot;designing-a-database-with-ef-core-and-c&quot;&gt;Designing a Database with EF Core and C#&lt;/h2&gt;

&lt;p&gt;EF Core supports multiple design philosophies, but the one I’m fond of is Code-First. Code first lets you design C# models, which EF Core will translate into a database schema. Create a folder at the root of your web application named &lt;strong&gt;“Models”&lt;/strong&gt; and create a new file called &lt;strong&gt;“Database.cs”&lt;/strong&gt;. Add the following content to the file. This code contains our first table and our &lt;code&gt;DbContext&lt;/code&gt; implementation.&lt;/p&gt;

&lt;p&gt;Adjust the namespace according to your project’s namespace if you’d like.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.EntityFrameworkCore;

namespace WebApplication4.Models;

public class Database : DbContext
{
    public Database(DbContextOptions&amp;lt;Database&amp;gt; options)
        : base(options)
    {}
    
    public DbSet&amp;lt;Person&amp;gt; People =&amp;gt; Set&amp;lt;Person&amp;gt;();
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; } = &quot;&quot;;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code will create a new “People” table with the columns of &lt;code&gt;Id&lt;/code&gt;, &lt;code&gt;Name&lt;/code&gt;, and &lt;code&gt;CreatedAt&lt;/code&gt;. You’ll also notice that our &lt;code&gt;Database&lt;/code&gt; class takes a parameter of &lt;code&gt;DbContextOptions&amp;lt;Database&amp;gt;&lt;/code&gt;; this is how you configure our database settings. The following section will show you how to set up values like connection strings and database providers.&lt;/p&gt;

&lt;h2 id=&quot;services-collection-and-configuring-our-dbcontext&quot;&gt;Services Collection and Configuring Our DbContext&lt;/h2&gt;

&lt;p&gt;You’ll need to register the type with ASP.NET Core’s services collection to take advantage of your newly created’ Database’ class. The registration process allows you to set up everything just the way you want, with options like database provider, logging, interceptors, and more. For this guide, let’s keep it simple. Add the following lines of code in your &lt;code&gt;Program.cs&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;builder.Services.AddDbContext&amp;lt;Database&amp;gt;(options =&amp;gt; {
    var config = builder.Configuration;
    var connectionString = config.GetConnectionString(&quot;database&quot;);
    
    options.UseSqlite(connectionString);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll notice that you’re using the configuration to get a connection string. So what does the configuration file look like? In your &lt;code&gt;appSettings.Development.json&lt;/code&gt; file, you’ll have the following.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;DetailedErrors&quot;: true,
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft.AspNetCore&quot;: &quot;Warning&quot;
    }
  },
  &quot;ConnectionStrings&quot;: {
    &quot;database&quot;: &quot;Data Source=database.db&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here you can add your connection strings and read them in code. &lt;strong&gt;I recommend storing connection strings in environment variables or cloud-specific settings providers when running your application in production settings.&lt;/strong&gt; Do not store sensitive information in source control under any circumstance.&lt;/p&gt;

&lt;p&gt;The next step is to create our database instance using database migrations and EF Core tooling.&lt;/p&gt;

&lt;h2 id=&quot;ef-core-migrations-and-databases&quot;&gt;EF Core Migrations and Databases&lt;/h2&gt;

&lt;p&gt;We have most of the working parts of our application set in place, but we still haven’t touched a database. That changes now. You’ll be creating your first migration from the command line. From the root directory of your solution, type the following command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;dotnet ef migrations add &quot;Initial&quot; --project WebApplication4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Be sure you change the &lt;code&gt;--project&lt;/code&gt; argument to match your project’s name. You can also exclude this argument by executing the command from the web application’s root directory instead of the solution directory.&lt;/p&gt;

&lt;p&gt;When executed correctly, you should see a new “Migrations” folder in your web application project and a timestamped migration named “Initial”. Opening the file will show the C# to Database schema translation that EF Core performed on your behalf.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace WebApplication4.Migrations
{
    /// &amp;lt;inheritdoc /&amp;gt;
    public partial class Initial : Migration
    {
        /// &amp;lt;inheritdoc /&amp;gt;
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: &quot;People&quot;,
                columns: table =&amp;gt; new
                {
                    Id = table.Column&amp;lt;int&amp;gt;(type: &quot;INTEGER&quot;, nullable: false)
                        .Annotation(&quot;Sqlite:Autoincrement&quot;, true),
                    Name = table.Column&amp;lt;string&amp;gt;(type: &quot;TEXT&quot;, nullable: false),
                    CreatedAt = table.Column&amp;lt;DateTime&amp;gt;(type: &quot;TEXT&quot;, nullable: false)
                },
                constraints: table =&amp;gt;
                {
                    table.PrimaryKey(&quot;PK_People&quot;, x =&amp;gt; x.Id);
                });
        }

        /// &amp;lt;inheritdoc /&amp;gt;
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: &quot;People&quot;);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s apply this to a database. Running the following command will use the connection string in your app settings. Be sure it is a local developer instance of a database.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;dotnet ef database update --project WebApplication4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re using SQLite, you should now see a &lt;code&gt;database.db&lt;/code&gt; or file with the same name as is found in your connection string. If you’re using another database provider, you can now see the EF Core-created tables in your database instance.&lt;/p&gt;

&lt;p&gt;For production purposes, I recommend you run migrations outside the running application. A lot can go wrong with database migration, and you don’t want a lousy migration to stop your application from running. That said, you can run migrations from your application’s startup for local development purposes. As an optional step, you can add the following migration code to your “Program.cs” file, below the call to &lt;code&gt;var app = builder.Build();&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;if (app.Environment.IsDevelopment())
{
    // migrate database, only during development
    using var scope = app.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService&amp;lt;Database&amp;gt;();
    await db.Database.MigrateAsync();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s start using our &lt;code&gt;DbContext&lt;/code&gt; and database instance.&lt;/p&gt;

&lt;h2 id=&quot;using-a-dbcontext-in-a-razor-page&quot;&gt;Using a DbContext in a Razor Page&lt;/h2&gt;

&lt;p&gt;Our goal in this section is to use our &lt;code&gt;Database&lt;/code&gt; class to read and write to our &lt;code&gt;People&lt;/code&gt; table. If you’re following along, you should have an &lt;code&gt;Index.cshtml&lt;/code&gt; along with an &lt;code&gt;Index.cshtml.cs&lt;/code&gt; file under a &lt;code&gt;Pages&lt;/code&gt; directory. We’ll be modifying the &lt;code&gt;Index.cshtml.cs&lt;/code&gt; type to pass in a &lt;code&gt;Database&lt;/code&gt; parameter to the constructor. So let’s start with the most straightforward modification of constructor injection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.AspNetCore.Mvc.RazorPages;
using WebApplication4.Models;

namespace WebApplication4.Pages;

public class IndexModel : PageModel
{
    private readonly ILogger&amp;lt;IndexModel&amp;gt; _logger;
    private readonly Database _database;

    public Person? Person { get; set; }
    
    public IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger, Database database)
    {
        _logger = logger;
        _database = database;
    }

    public void OnGet()
    {
        Person = _database
            .People
            .OrderByDescending(p =&amp;gt; p.CreatedAt)
            .FirstOrDefault();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above code takes in a &lt;code&gt;Database&lt;/code&gt; instance and sets it to a private member. Then, on the page’s response to a &lt;code&gt;GET&lt;/code&gt; HTTP request, the &lt;code&gt;OnGet&lt;/code&gt; method will query for the latest person in the &lt;code&gt;People&lt;/code&gt; table. You can set the result to the &lt;code&gt;Person&lt;/code&gt; property. You’ll use this later when building the view.&lt;/p&gt;

&lt;p&gt;Let’s also take a look at parameter injection. You’ll need to add an &lt;code&gt;OnPost&lt;/code&gt; method and a new bindable property. The new method will also take a &lt;code&gt;Database&lt;/code&gt; instance as an argument, but you’ll need a &lt;code&gt;FromServices&lt;/code&gt; attribute to tell ASP.NET Core to resolve this value from the services collection. Let’s look at the updated file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using WebApplication4.Models;

namespace WebApplication4.Pages;

public class IndexModel : PageModel
{
    private readonly ILogger&amp;lt;IndexModel&amp;gt; _logger;
    private readonly Database _database;

    public Person? Person { get; set; }
    
    public IndexModel(ILogger&amp;lt;IndexModel&amp;gt; logger, Database database)
    {
        _logger = logger;
        _database = database;
    }

    public void OnGet()
    {
        Person = _database
            .People
            .OrderByDescending(p =&amp;gt; p.CreatedAt)
            .FirstOrDefault();
    }

    [BindProperty, Required, DisplayName(&quot;Person&apos;s Name&quot;)]
    public string? Name { get; set; }
    
    public async Task&amp;lt;IActionResult&amp;gt; OnPost([FromServices] Database db)
    {
        if (ModelState.IsValid)
        {
            Person person = new() { Name = Name! };
            db.People.Add(person);
            await db.SaveChangesAsync();
            return RedirectToPage();
        }

        // show validation messages
        return Page();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before continuing to the Razor view, let’s discuss the &lt;code&gt;OnPost&lt;/code&gt; implementation. It’s a critical practice when developing applications to adhere to a &lt;strong&gt;GET-POST-Redirect&lt;/strong&gt; pattern. The pattern keeps your users from accidentally refreshing the page and submitting multiple requests for the same action. The method uses a return value of &lt;code&gt;IActionResult&lt;/code&gt; so you can return numerous interface implementations, including &lt;code&gt;RedirectToPage&lt;/code&gt; and &lt;code&gt;Page&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition to handling a form post, we need properties to bind to our ASP.NET Core Razor Pages form. In this case, we only have one property of &lt;code&gt;Name&lt;/code&gt;. In Razor Pages, the page model is where you add all your form fields, but you can also certainly move them into individual models. If you’re using ASP.NET Core MVC, you might apply a “View Model” approach, which will also work here.&lt;/p&gt;

&lt;p&gt;Let’s write some Razor!&lt;/p&gt;

&lt;h2 id=&quot;creating-an-aspnet-core-razor-form&quot;&gt;Creating an ASP.NET Core Razor Form&lt;/h2&gt;

&lt;p&gt;The culmination of our work has led you to the Razor view, where you’ll be adding a form to add new &lt;code&gt;Person&lt;/code&gt; instances to your database. First, let’s look at the view and break down its parts.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cshtml&quot;&gt;@page
@model IndexModel
@{
    ViewData[&quot;Title&quot;] = &quot;Home page&quot;;
}

@if (Model.Person is {} person)
{
    &amp;lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&amp;gt;
        Hello &amp;lt;span class=&quot;alert-link&quot;&amp;gt;@person.Name&amp;lt;/span&amp;gt;! 
        Nice to meet you.
    &amp;lt;/div&amp;gt;
}

&amp;lt;form asp-page=&quot;Index&quot; method=&quot;post&quot;&amp;gt;
    &amp;lt;div asp-validation-summary=&quot;All&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;input-group&quot;&amp;gt;
        &amp;lt;div class=&quot;form-group mb-2&quot;&amp;gt;
            &amp;lt;label asp-for=&quot;Name&quot;&amp;gt;&amp;lt;/label&amp;gt;
            &amp;lt;input class=&quot;form-control&quot; asp-for=&quot;Name&quot;&amp;gt;
            &amp;lt;span asp-validation-for=&quot;Name&quot; class=&quot;invalid-feedback&quot;&amp;gt;&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button class=&quot;btn btn-primary&quot; type=&quot;submit&quot;&amp;gt;Save Person&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;form&lt;/code&gt; element uses &lt;strong&gt;TagHelpers&lt;/strong&gt; to use the &lt;code&gt;IndexModel&lt;/code&gt; properties to build our form. We are also telling the form to &lt;code&gt;POST&lt;/code&gt; the form to our page handler of &lt;code&gt;OnPost&lt;/code&gt; using the &lt;code&gt;asp-page&lt;/code&gt; attribute. Finally, there’s a submit button.&lt;/p&gt;

&lt;p&gt;Above our form, we’ve also added usage of our &lt;code&gt;Person&lt;/code&gt; property. If it is not null, we’ll show an alert from the last entry in the database.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1024/https://khalidabuhakmeh.com/assets/images/posts/misc/how-to-use-entity-framework-core-aspnet-core-result.png 1024w&quot; sizes=&quot;100vw&quot; alt=&quot;asp.net core web page showing data from entity framework core&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;634&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Running your application now, you’ll be able to save and read data in an ASP.NET Core application using Entity Framework Core. Congratulations!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Getting a working ASP.NET Core application using EF Core can seem tedious, but in most cases, the “plumbing” work is done once upfront and never touched again.&lt;/p&gt;

&lt;p&gt;You’ll spend most of your time adding a C# class to your &lt;code&gt;DbContext&lt;/code&gt;, adding new database migrations, and then plumbing that entity to a Razor page. That’s the positive side of this approach; adding new functionality is boring with few surprises. When building and maintaining applications, boring is a good thing.&lt;/p&gt;

&lt;p&gt;While I certainly didn’t go into every possible detail, this quick-start guide should have you up in no time. If you have any specific questions or have issues, please contact me at @khalidabuhakmeh@mastodon.social or use the contact form on the blog.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my blog posts.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/how-to-use-entity-framework-core-in-aspnet-core</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/how-to-use-entity-framework-core-in-aspnet-core</guid>
        
        <category>dotnet,</category>
        
        <category>aspnet,</category>
        
        <category>entity-framework</category>
        
        
      </item>
    
      <item>
        <title>Register MAUI Views and ViewModels with Scrutor</title>
        <description>&lt;p&gt;As a developer advocate at &lt;a href=&quot;https://jetbrains.com&quot;&gt;JetBrains&lt;/a&gt;, I find myself exploring technologies in nooks and crannies of the ecosystem previously out of reach. As a lifelong proponent of the web, mobile development has always been on my list to explore, but I rarely found the time to do so. One of the latest technologies I am dabbling with is Multi-platform App UI, more commonly referred to as MAUI.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to use the packages &lt;strong&gt;CommunityToolkit.Mvvm&lt;/strong&gt; and &lt;strong&gt;Scrutor&lt;/strong&gt; to quickly register your XAML views and the corresponding ViewModels for a more convenient approach.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;communitytoolkitmvvm-and-the-mvvm-pattern&quot;&gt;CommunityToolkit.Mvvm and the MVVM pattern&lt;/h2&gt;

&lt;p&gt;The Model-View-View-Model pattern, also referred to as MVVM, is an approach that separates the logic of your views from the language of the View. In the case of MAUI, that view language is typically XAML. Utilizing the pattern leads to a few positive side effects:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Your &lt;strong&gt;ViewModels&lt;/strong&gt; are much more straightforward to test, with the bulk of your logic exposed through properties and commands.&lt;/li&gt;
  &lt;li&gt;Your &lt;strong&gt;Views&lt;/strong&gt; are simpler, binding to properties and commands rather than directly to members on the specific &lt;code&gt;ContentPage&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;In MAUI, both &lt;code&gt;ContentPage&lt;/code&gt; and &lt;strong&gt;ViewModels&lt;/strong&gt; can support dependency injection arguments, allowing for the composition of app functionality.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m sure there are other benefits to using the MVVM pattern, but these immediately spring to mind when compared to the alternative of dumping all logic in a &lt;code&gt;ContentPage&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CommunityToolkit.Mvvm&lt;/code&gt; package includes helpers to make adopting the MVVM pattern more straightforward and performant. &lt;code&gt;CommunityToolkit.Mvvm&lt;/code&gt; uses source generators to generate the tedious parts of building MAUI apps, most notably the implementation of &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and &lt;code&gt;ICommand&lt;/code&gt; instances.&lt;/p&gt;

&lt;p&gt;Let’s start with a simple update of the default MAUI template. Next, we’ll add a new &lt;code&gt;MainPageViewModel&lt;/code&gt; and move most of the app’s logic from the &lt;code&gt;MainPage.xaml.cs&lt;/code&gt; file to our new class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;a href=&quot;https://putridparrot.com/blog/mvvm-with-the-mvvm-community-toolkit/&quot;&gt;This sample is from a blog post by Mark Timmings. Check it out here.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace MyFirstMauiApp.ViewModels;

public partial class MainPageViewModel : ObservableObject
{
    [ObservableProperty] int count;
    [ObservableProperty] private string text;
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(IncrementCountCommand))]
    bool canIncrement;
    
    bool CanExecuteIncrement() =&amp;gt; canIncrement;

    [RelayCommand(CanExecute = nameof(CanExecuteIncrement))]
    void IncrementCount()
    {
        Count++;
        Text = Count == 1 
            ? $&quot;Clicked {count} time&quot; 
            : $&quot;Clicked {count} times&quot;;
        
        SemanticScreenReader.Announce(Text);
    }
    
    partial void OnCanIncrementChanged(bool value)
    {
        Debug.WriteLine(&quot;OnCanIncrementChanged called&quot;);
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we’ll update our &lt;code&gt;MainPage.xaml.cs&lt;/code&gt; code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using MyFirstMauiApp.ViewModels;

namespace MyFirstMauiApp;

public partial class MainPage : ContentPage
{
    public MainPage(MainPageViewModel model)
    {
        InitializeComponent();
        BindingContext = model;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll also need to update the XAML to take advantage of our new &lt;code&gt;MainPageViewModel&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&amp;gt;
&amp;lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
             xmlns:viewModels=&quot;clr-namespace:MyFirstMauiApp.ViewModels&quot;
             x:Class=&quot;MyFirstMauiApp.MainPage&quot;
             x:DataType=&quot;viewModels:MainPageViewModel&quot;&amp;gt;

    &amp;lt;ScrollView&amp;gt;
        &amp;lt;VerticalStackLayout
            Spacing=&quot;25&quot;
            Padding=&quot;30,0&quot;
            VerticalOptions=&quot;Center&quot;&amp;gt;

            &amp;lt;Image
                Source=&quot;dotnet_bot.png&quot;
                SemanticProperties.Description=&quot;Cute dot net bot waving hi to you!&quot;
                HeightRequest=&quot;200&quot;
                HorizontalOptions=&quot;Center&quot; /&amp;gt;

            &amp;lt;Label
                Text=&quot;Hello, World!&quot;
                SemanticProperties.HeadingLevel=&quot;Level1&quot;
                FontSize=&quot;32&quot;
                HorizontalOptions=&quot;Center&quot; /&amp;gt;

            &amp;lt;Label
                Text=&quot;{Binding Text}&quot;
                SemanticProperties.HeadingLevel=&quot;Level2&quot;
                SemanticProperties.Description=&quot;Welcome to dot net Multi platform App U I&quot;
                FontSize=&quot;18&quot;
                HorizontalOptions=&quot;Center&quot; /&amp;gt;
            
            &amp;lt;CheckBox
                IsChecked=&quot;{Binding CanIncrement}&quot; /&amp;gt;

            &amp;lt;Button
                x:Name=&quot;CounterBtn&quot;
                Text=&quot;{Binding Count, StringFormat=&apos;Click me ({0})&apos;}&quot;
                SemanticProperties.Hint=&quot;Counts the number of times you click&quot;
                Command=&quot;{Binding IncrementCountCommand}&quot;
                HorizontalOptions=&quot;Center&quot; /&amp;gt;

        &amp;lt;/VerticalStackLayout&amp;gt;
    &amp;lt;/ScrollView&amp;gt;

&amp;lt;/ContentPage&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you were to run this application now, you’d get the following &lt;code&gt;MissingMethodException&lt;/code&gt; exception.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;Unhandled Exception:
System.MissingMethodException: No parameterless constructor defined for type &apos;MyFirstMauiApp.MainPage&apos;.
   at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle)
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at MyFirstMauiApp.Program.Main(String[] args) in /Users/khalidabuhakmeh/RiderProjects/MyFirstMauiApp/MyFirstMauiApp/Platforms/iOS/Program.cs:line 13
2023-01-17 14:15:13.288973-0500 MyFirstMauiApp[40948:8367336] Unhandled managed exception: No parameterless constructor defined for type &apos;MyFirstMauiApp.MainPage&apos;. (System.MissingMethodException)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;MAUI doesn’t know how to instantiate any classes mentioned in this sample yet. Let’s fix that.&lt;/p&gt;

&lt;h2 id=&quot;using-scrutor-to-register-views-and-viewmodels&quot;&gt;Using Scrutor to Register Views and ViewModels&lt;/h2&gt;

&lt;p&gt;In the context of an MVVM-powered MAUI app, there are two essential elements: The View and the ViewModel. These concepts are represented by the types &lt;code&gt;ContentPage&lt;/code&gt; and &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/khellang/Scrutor&quot;&gt;Scrutor&lt;/a&gt; can scan for those types and register the instances as themselves with &lt;strong&gt;singleton&lt;/strong&gt; lifetimes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using Microsoft.Extensions.Logging;
using CommunityToolkit.Mvvm.ComponentModel;

namespace MyFirstMauiApp;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();

        // The important part
        builder.Services.Scan(s =&amp;gt; s
            .FromAssemblyOf&amp;lt;App&amp;gt;()
            .AddClasses(f =&amp;gt; f.AssignableToAny(
                    typeof(ContentPage), 
                    typeof(ObservableObject))
                )
                .AsSelf()
                .WithSingletonLifetime()
        );
        // end of important part
        
        builder
            .UseMauiApp&amp;lt;App&amp;gt;().ConfigureFonts(fonts =&amp;gt;
            {
                fonts.AddFont(&quot;OpenSans-Regular.ttf&quot;, &quot;OpenSansRegular&quot;);
                fonts.AddFont(&quot;OpenSans-Semibold.ttf&quot;, &quot;OpenSansSemibold&quot;);
            });
        
#if DEBUG
        builder.Logging.AddDebug();
#endif
        return builder.Build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we start the application, we should see our MVVM-powered MAUI application.&lt;/p&gt;

&lt;p&gt;The advantage to using Scrutor in this instance is that we can continue to expand our application’s functionality with Views and ViewModels. They should all be part of the services collection and work with dependency injection.&lt;/p&gt;

&lt;p&gt;I’ve chosen to register all elements as &lt;strong&gt;singelton&lt;/strong&gt; since, in most cases, a mobile application is limited to a single user, and having types registered as &lt;strong&gt;scoped&lt;/strong&gt; or &lt;strong&gt;transient&lt;/strong&gt; is a waste of resources.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this blog post, and please let me know what kind of MAUI apps you’re building. As this is still a burgeoning community and technology, there’s still a lot to learn.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading and sharing my posts.&lt;/p&gt;
</description>
        <pubDate>Tue, 31 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/register-maui-views-and-viewmodels-with-scrutor</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/register-maui-views-and-viewmodels-with-scrutor</guid>
        
        <category>dotnet,</category>
        
        <category>MAUI</category>
        
        
      </item>
    
      <item>
        <title>Programming SVGs with C#</title>
        <description>&lt;p&gt;One of my hobbies to create graphics using my favorite photo editing tool, &lt;a href=&quot;https://www.pixelmator.com/pro/&quot;&gt;Pixelmator Pro&lt;/a&gt;. It’s a fantastic tool; anyone on macOS should add it to their &lt;strong&gt;Applications&lt;/strong&gt; folder. One of the benefits of using a photo-editing tool is the ability to create Scalable Vector Graphics (SVG). SVGs are an XML-based format that allows you to edit and manipulate the content of an image with a text editor if you choose, but I wouldn’t recommend it. Photo-editing tools are much better at creating graphics, but SVGs provide a way to extend and repurpose existing assets.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how you can take an existing SVG and create a programmable visual asset with some C# code. Let’s get started.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;whats-an-svg&quot;&gt;What’s an SVG?&lt;/h2&gt;

&lt;p&gt;Scalable Vector Graphics is an XML-based markup language, not too dissimilar to HTML, allowing users to create two-dimensional based vector graphics. A standard format used across multiple image editors to create infinitely scalable assets is widely supported by major browser vendors. First, let’s look at an example SVG, which we’ll program later with C#.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!-- Generated by Pixelmator Pro 3.2.3 --&amp;gt;
&amp;lt;svg width=&quot;1000&quot; height=&quot;1000&quot; viewBox=&quot;0 0 1000 1000&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot;&amp;gt;
    &amp;lt;path id=&quot;Color-Fill&quot; fill=&quot;#ff6900&quot; stroke=&quot;none&quot; d=&quot;M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z&quot;/&amp;gt;
    &amp;lt;g&amp;gt;
        &amp;lt;path id=&quot;Logo-Shape&quot; fill=&quot;#020303&quot; fill-rule=&quot;evenodd&quot; stroke=&quot;none&quot; d=&quot;M 832.5 500 C 832.5 316.365356 683.634644 167.5 500 167.5 C 316.365326 167.5 167.5 316.365356 167.5 500 C 167.5 683.634644 316.365326 832.5 500 832.5 C 683.634644 832.5 832.5 683.634644 832.5 500 Z&quot;/&amp;gt;
        &amp;lt;text id=&quot;Beyond-The-Idea&quot; xml:space=&quot;preserve&quot; x=&quot;50%&quot; y=&quot;50%&quot; text-anchor=&quot;middle&quot;&amp;gt;
            &amp;lt;tspan id=&quot;Top&quot; x=&quot;50%&quot; y=&quot;493&quot; font-family=&quot;JetBrains Mono&quot; font-size=&quot;111.9625&quot; fill=&quot;#ffffff&quot; xml:space=&quot;preserve&quot;&amp;gt;BEYOND&amp;lt;/tspan&amp;gt;
            &amp;lt;tspan id=&quot;Bottom&quot; x=&quot;50%&quot; y=&quot;604.2&quot; font-family=&quot;JetBrains Mono&quot; font-size=&quot;111.9625&quot; fill=&quot;#ffffff&quot; xml:space=&quot;preserve&quot;&amp;gt;THE IDEA&amp;lt;/tspan&amp;gt;
        &amp;lt;/text&amp;gt;
    &amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This SVG produces the following visual output.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/programmable-svgs/template.svg&quot; alt=&quot;SVG Template&quot; /&gt;&lt;/p&gt;

&lt;p&gt;An added benefit of being markup is you can typically target any element with styling or explicit color fills and strokes. The flexibility makes one asset infinitely configurable.&lt;/p&gt;

&lt;p&gt;Neat, right?! So how do you take this XML and create a programmable image?&lt;/p&gt;

&lt;h2 id=&quot;hurndles-to-programming-svgs&quot;&gt;Hurndles to Programming SVGs&lt;/h2&gt;

&lt;p&gt;By the end of this section, we’ll have loaded an SVG into a .NET application’s memory, modified text elements of the SVG, and rendered the image to disk as a PNG. We’ll also create a wrapper class to make using your new SVG easier for other developers.&lt;/p&gt;

&lt;p&gt;Before we start, let’s talk about caveats you’re likely to encounter. The code I’ll be showing can overcome these issues, while you’ll need to figure others out for your use case.&lt;/p&gt;

&lt;p&gt;If you want to follow along, create a new console application and add the &lt;a href=&quot;https://www.nuget.org/packages/Svg&quot;&gt;&lt;code&gt;Svg&lt;/code&gt; NuGet package&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;what-about-the-fonts&quot;&gt;What about the fonts?&lt;/h3&gt;

&lt;p&gt;The first issue you’ll likely run into is &lt;strong&gt;fonts&lt;/strong&gt;. SVGs are a markup language, and text elements reference fonts. Therefore, if you use a non-standard font (which is likely), you’re bound to run into rendering issues when you deploy your programmable SVG.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Svg&lt;/code&gt; package has a static type called &lt;code&gt;SvgFontManager&lt;/code&gt; which will let you load any font into the SVG rendering context.&lt;/p&gt;

&lt;p&gt;In the case of this sample, let’s add a font, &lt;code&gt;JetBrains Mono&lt;/code&gt;, to our assembly as an embedded resource, then load it into the font manager.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var assembly = Assembly.GetAssembly(typeof(PromotionalImage))!;
using var fontStream = assembly.GetManifestResourceStream(&quot;SvgFontEmbed.JetBrainsMono-Regular.ttf&quot;)!;
using var ms = new MemoryStream();
fontStream.CopyTo(ms);
// load font into font manager
SvgFontManager.PrivateFontDataList.Add(ms.ToArray());
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The font name of &lt;code&gt;JetBrains Mono&lt;/code&gt; is used in the SVG, as seen on the &lt;code&gt;tspan&lt;/code&gt; elements.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;tspan id=&quot;Top&quot; x=&quot;50%&quot; y=&quot;493&quot; font-family=&quot;JetBrains Mono&quot; font-size=&quot;111.9625&quot; fill=&quot;#ffffff&quot; xml:space=&quot;preserve&quot;&amp;gt;BEYOND&amp;lt;/tspan&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can add as many or as few fonts as your SVG requires. But, of course, you can also forget to add any fonts you know will be on the destination host.&lt;/p&gt;

&lt;h3 id=&quot;text-centering&quot;&gt;Text Centering&lt;/h3&gt;

&lt;p&gt;Another issue you may run into is the centering of text elements. While I mostly created the sample SVG in a photo editor, I manually modified the markup to adapt to variations in input. As a recommendation, you should change any numeric values for &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;y&lt;/code&gt; to use percentage values, thus keeping the spirit of the original image intact.&lt;/p&gt;

&lt;h3 id=&quot;using-html-colors-instead-of-rgb&quot;&gt;Using HTML colors instead of RGB&lt;/h3&gt;

&lt;p&gt;If you want to use HTML-based colors, you can use the &lt;code&gt;ColorTranslator&lt;/code&gt; class in &lt;code&gt;System.Drawing&lt;/code&gt; namespace.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;ColorTranslator.FromHtml(&quot;#840087&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Hexadecimal color representation is more common among image-editing apps, developers, and designers. Go with the flow.&lt;/p&gt;

&lt;h2 id=&quot;back-to-programming-an-svg&quot;&gt;Back To Programming an SVG&lt;/h2&gt;

&lt;p&gt;I thought I’d start with some of the issues I ran into before jumping into a programmable SVG because you’ll likely have to tinker with your SVG template to get the results you’re looking to produce.&lt;/p&gt;

&lt;p&gt;You’ll first want to add your SVG template and fonts into your console application or class library as embedded resources. Doing so will make sharing these images easier in the long run, as all assets will be part of your compiled artifact.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;None Remove=&quot;JetBrainsMono-Regular.ttf&quot; /&amp;gt;
  &amp;lt;EmbeddedResource Include=&quot;JetBrainsMono-Regular.ttf&quot; /&amp;gt;
  &amp;lt;None Remove=&quot;template.svg&quot; /&amp;gt;
  &amp;lt;EmbeddedResource Include=&quot;template.svg&quot; /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’ll be able to access these resources using the following code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;static PromotionalImage()
{
    var assembly = Assembly.GetAssembly(typeof(PromotionalImage))!;
    using var fontStream = assembly.GetManifestResourceStream(&quot;SvgFontEmbed.JetBrainsMono-Regular.ttf&quot;)!;
    using var ms = new MemoryStream();
    fontStream.CopyTo(ms);
    // load font into font manager
    SvgFontManager.PrivateFontDataList.Add(ms.ToArray());

    using var svgStream = assembly.GetManifestResourceStream(&quot;SvgFontEmbed.template.svg&quot;)!;
    using var textReader = new StreamReader(svgStream);

    SvgXml = textReader.ReadToEnd();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Your next step is to look at your SVG and determine all the identifiers you want your users to modify, along with the types of each element. In the case of the example above, we’ll be converting the background color and the two text spans of &lt;code&gt;Top&lt;/code&gt; and &lt;code&gt;Bottom&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Drawing;
using System.Reflection;
using Svg;

public static class PromotionalImage
{
    private static string SvgXml;
    
    static PromotionalImage()
    {
        var assembly = Assembly.GetAssembly(typeof(PromotionalImage))!;
        using var fontStream = assembly.GetManifestResourceStream(&quot;SvgFontEmbed.JetBrainsMono-Regular.ttf&quot;)!;
        using var ms = new MemoryStream();
        fontStream.CopyTo(ms);
        // load font into font manager
        SvgFontManager.PrivateFontDataList.Add(ms.ToArray());

        using var svgStream = assembly.GetManifestResourceStream(&quot;SvgFontEmbed.template.svg&quot;)!;
        using var textReader = new StreamReader(svgStream);

        SvgXml = textReader.ReadToEnd();
    }

    public static SvgDocument Create(string topText, string bottomText, string? bgColor = null)
    {
        var document = SvgDocument.FromSvg&amp;lt;SvgDocument&amp;gt;(SvgXml);

        var texts = document.Children.FindSvgElementsOf&amp;lt;SvgTextSpan&amp;gt;().ToList();
        texts.First(t =&amp;gt; t.ID == &quot;Top&quot;).Text = topText;
        texts.First(t =&amp;gt; t.ID == &quot;Bottom&quot;).Text = bottomText;
        
        if (bgColor is { })
        {
            var bg = document.Children.Where(x =&amp;gt; x.ID == &quot;Color-Fill&quot;)
                .Where(e =&amp;gt; e is SvgPath)
                .Cast&amp;lt;SvgPath&amp;gt;()
                .First();

            bg.Fill = new SvgColourServer(ColorTranslator.FromHtml(bgColor));
        }

        return document;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s look at the steps in the &lt;code&gt;Create&lt;/code&gt; method.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;First, we create a new SVG document in memory. We want to do that to work with a fresh instance every time.&lt;/li&gt;
  &lt;li&gt;Second, we find the text spans in our SVG by their identifiers and set the new values set by the user.&lt;/li&gt;
  &lt;li&gt;Finally, we find the background of &lt;code&gt;Color-Fill&lt;/code&gt; and set the color to the hexadecimal value passed in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see how we can use this new class in code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;using System.Drawing.Imaging;

var image = PromotionalImage.Create(&quot;DROP&quot;, &quot;THE DOT&quot;, &quot;#840087&quot;);
image.Draw().Save(&quot;result.png&quot;, ImageFormat.Png);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The resulting image is a mutation of our original template.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_800/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png&quot; srcset=&quot;https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_320/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png 320w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_540/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png 540w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_760/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png 760w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_980/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png 980w, https://res.cloudinary.com/abuhakmeh/image/fetch/c_limit,f_auto,q_auto,w_1000/https://khalidabuhakmeh.com/assets/images/posts/programmable-svgs/result.png 1000w&quot; sizes=&quot;100vw&quot; alt=&quot;drop the dot from svg template&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;1000&quot; crossorigin=&quot;anonymous&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yes! You did it. You just programmed an SVG using C#.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With SVGs and .NET, you can procedurally generate an infinite amount of assets with minimal effort. The &lt;code&gt;Svg&lt;/code&gt; library on NuGet supports many markup elements required to change any starting template dramatically. You could go so far as to add new paths, change colors, modify the text, switch fonts, or do whatever you wish. Embedding the resources into a class library would allow you to ship a generator via a NuGet package to use in various situations. The possibilities are limitless.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, and as always, thanks for reading.&lt;/p&gt;

</description>
        <pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://khalidabuhakmeh.com/programming-svgs-with-csharp-dotnet</link>
        <guid isPermaLink="true">https://khalidabuhakmeh.com/programming-svgs-with-csharp-dotnet</guid>
        
        <category>dotnet</category>
        
        
      </item>
    
  </channel>
</rss>
