<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Khalid Abuhakmeh</title><description>Senior Customer Success Engineer at Duende Software. Content Creator. Opinions are my own.</description><link>https://khalidabuhakmeh.com/</link><item><title>C# 15 Union Types: Build Serializable Workflows</title><link>https://khalidabuhakmeh.com/posts/csharp-15-union-workflows/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/csharp-15-union-workflows/</guid><description>Build a C# 15 union workflow on .NET 11: one Next method, typed inputs, exhaustive results, and JSON state you can save and rehydrate.</description><pubDate>Mon, 12 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every few years I end up flirting with the idea of a &lt;a href=&quot;https://khalidabuhakmeh.com/state-machines-light-switches-and-space-travel-with-stateless-and-dotnet-8&quot;&gt;state machine&lt;/a&gt;, and every time I remember how complicated it gets. With C# 15, .NET ships union types (what many of us call a C# discriminated union), and I wanted to see if they could shrink that problem down to one state value and one method.&lt;/p&gt;
&lt;p&gt;In this post, we’ll build a serializable workflow on .NET 11 where &lt;code&gt;Next&lt;/code&gt; always returns a member of a union, and we’ll save and rehydrate it as JSON.&lt;/p&gt;
&lt;p&gt;Everything here ran on &lt;code&gt;11.0.100-rc.1&lt;/code&gt;, so expect details to shift before general availability. &lt;em&gt;Updated: October 2026.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-are-c-15-unions&quot;&gt;&lt;a href=&quot;#what-are-c-15-unions&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Are C# 15 Unions?”&quot;&gt;What Are C# 15 Unions?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A C# 15 union declares a type that holds exactly one value from a closed list of case types.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Success&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Failure&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Success&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Failure&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Code&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public union Result(Success, Failure);public record Success(string Message);public record Failure(int Code);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;These are &lt;strong&gt;type unions&lt;/strong&gt;, not enum-style tagged cases. The cases are ordinary types you declare yourself, and &lt;a href=&quot;https://khalidabuhakmeh.com/avoid-csharp-9-record-gotchas&quot;&gt;records&lt;/a&gt; work well for them.&lt;/li&gt;
&lt;li&gt;Cases are &lt;strong&gt;not nested&lt;/strong&gt; in the union. You write &lt;code&gt;Result r = new Success(&quot;ok&quot;);&lt;/code&gt; and the compiler adds the implicit conversion.&lt;/li&gt;
&lt;li&gt;The compiler generates a &lt;strong&gt;struct&lt;/strong&gt; that stores the active case in a single &lt;code&gt;object?&lt;/code&gt; &lt;code&gt;Value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;switch&lt;/code&gt; &lt;strong&gt;expression&lt;/strong&gt; that covers every case is exhaustive, so there’s no default arm. If you need a refresher on the syntax, see my &lt;a href=&quot;https://khalidabuhakmeh.com/csharp-pattern-matching-quick-guide-and-examples&quot;&gt;C# pattern matching quick guide&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Success&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; message) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; message,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Failure&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; code) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Error &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;static string Describe(Result r) =&gt; r switch{    Success(var message) =&gt; message,    Failure(var code) =&gt; $&amp;quot;Error {code}&amp;quot;,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That exhaustiveness is the reason I wanted unions for workflows. Add a new case, and the compiler points at every place that forgot to handle it.&lt;/p&gt;
&lt;p&gt;To follow along, install the .NET 11 SDK and target &lt;code&gt;net11.0&lt;/code&gt;. C# 15 is the default language version there, but I pin it to be explicit.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;net11.0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;LangVersion&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;15.0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;LangVersion&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;PropertyGroup&gt;  &lt;TargetFramework&gt;net11.0&lt;/TargetFramework&gt;  &lt;LangVersion&gt;15.0&lt;/LangVersion&gt;&lt;/PropertyGroup&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you use Homebrew on macOS, its &lt;code&gt;dotnet&lt;/code&gt; may be first on your &lt;code&gt;PATH&lt;/code&gt; and quietly use an older SDK. Check with &lt;code&gt;dotnet --version&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;four-unions-one-method&quot;&gt;&lt;a href=&quot;#four-unions-one-method&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Four Unions, One Method”&quot;&gt;Four Unions, One Method&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A workflow, in my definition, is state plus a single method. Four small unions describe everything that moves through it:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Union&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Cases&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OrderState&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where is the workflow?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Drafted&lt;/code&gt;, &lt;code&gt;Submitted&lt;/code&gt;, &lt;code&gt;InReview&lt;/code&gt;, &lt;code&gt;Approved&lt;/code&gt;, &lt;code&gt;Rejected&lt;/code&gt;, &lt;code&gt;Fulfilled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;StepInput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What is the caller sending in?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NoInput&lt;/code&gt;, &lt;code&gt;ApprovalAnswer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InputRequest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What does a waiting step need?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ApprovalRequest&lt;/code&gt;, &lt;code&gt;ManagerApprovalRequest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;StepResult&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What should the caller do next?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Advance&lt;/code&gt;, &lt;code&gt;AwaitInput&lt;/code&gt;, &lt;code&gt;Finish&lt;/code&gt;, &lt;code&gt;Fail&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Where the workflow is. Each case carries only the data that state needs.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Reason&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What the caller sends in.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Comment&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What a waiting step asks the caller for.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Question&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Question&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What Next() tells the caller to do.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Reason&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// Where the workflow is. Each case carries only the data that state needs.public union OrderState(Drafted, Submitted, InReview, Approved, Rejected, Fulfilled);public record Drafted(string OrderId, decimal Amount);public record Submitted(string OrderId, decimal Amount);public record InReview(string OrderId, decimal Amount);public record Approved(string OrderId, decimal Amount);public record Rejected(string OrderId, string Reason);public record Fulfilled(string OrderId);// What the caller sends in.public union StepInput(NoInput, ApprovalAnswer);public record NoInput;public record ApprovalAnswer(bool Approved, string? Comment);// What a waiting step asks the caller for.public union InputRequest(ApprovalRequest, ManagerApprovalRequest);public record ApprovalRequest(string Question);public record ManagerApprovalRequest(string Question, decimal Amount);// What Next() tells the caller to do.public union StepResult(Advance, AwaitInput, Finish, Fail);public record Advance(OrderState State);public record AwaitInput(InputRequest Request);public record Finish(OrderState State);public record Fail(string Reason);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;StepResult&lt;/code&gt; is the contract. Every call to &lt;code&gt;Next&lt;/code&gt; returns one of four things, and the caller must handle all four:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Advance&lt;/code&gt;: the workflow moved, so the caller can call &lt;code&gt;Next&lt;/code&gt; again.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AwaitInput&lt;/code&gt;: it needs an answer, so the caller should collect one.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Finish&lt;/code&gt;: it reached a terminal state, so the caller should stop.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Fail&lt;/code&gt;: the input didn’t belong to this step, so the caller should handle the error.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-naming-rule-that-avoids-collisions&quot;&gt;&lt;a href=&quot;#a-naming-rule-that-avoids-collisions&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “A Naming Rule That Avoids Collisions”&quot;&gt;A Naming Rule That Avoids Collisions&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because union cases aren’t nested in the union, every case name shares a namespace with your other types. Naming by tense keeps them apart:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;States are past tense&lt;/strong&gt;, because they describe what has already happened: &lt;code&gt;Submitted&lt;/code&gt;, &lt;code&gt;Approved&lt;/code&gt;, &lt;code&gt;Rejected&lt;/code&gt;, &lt;code&gt;Fulfilled&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Results are present-tense instructions&lt;/strong&gt; to the caller: &lt;code&gt;Advance&lt;/code&gt;, &lt;code&gt;AwaitInput&lt;/code&gt;, &lt;code&gt;Finish&lt;/code&gt;, &lt;code&gt;Fail&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inputs and requests are nouns&lt;/strong&gt;: &lt;code&gt;ApprovalAnswer&lt;/code&gt;, &lt;code&gt;ManagerApprovalRequest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A state is a condition and a result is a command, so the sets never overlap, and the caller reads like a script. &lt;code&gt;Fail&lt;/code&gt; is a technical failure, like input sent to the wrong step. A business “no” such as &lt;code&gt;Rejected&lt;/code&gt; arrives as a &lt;code&gt;Finish&lt;/code&gt; carrying a &lt;code&gt;Rejected&lt;/code&gt; state.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-type-workflow-input&quot;&gt;&lt;a href=&quot;#how-do-you-type-workflow-input&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do You Type Workflow Input?”&quot;&gt;How Do You Type Workflow Input?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Make the input a union too. The tempting alternative is &lt;code&gt;Next(object? input)&lt;/code&gt; with type checks inside each step. That compiles, but the compiler can’t tell you what a step expects, and &lt;code&gt;null&lt;/code&gt; ends up meaning both “no input” and “a mistake”.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;StepInput&lt;/code&gt;, there’s no &lt;code&gt;null&lt;/code&gt; at all. &lt;code&gt;NoInput&lt;/code&gt; means “I’m just asking what’s next”, and every step handles each input case. A waiting step also tells the caller what it wants with a typed &lt;code&gt;InputRequest&lt;/code&gt;, instead of a prompt string.&lt;/p&gt;
&lt;h2 id=&quot;the-workflow&quot;&gt;&lt;a href=&quot;#the-workflow&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Workflow”&quot;&gt;The Workflow&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s the whole workflow class. &lt;code&gt;Next&lt;/code&gt; is one switch expression, so the compiler checks that every state, and every input for a state that waits, is handled.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; state;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;orderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(orderId, amount));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FromState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(state);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount))),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Approve submission for review?&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Submission not approved for review.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1000m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Manager approval required.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Manager rejected the order.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id))),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; next;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;terminal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; terminal;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Steps that don&apos;t wait for anything reject unexpected input.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;This step does not take input.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public sealed class OrderWorkflow{    public OrderState State { get; private set; }    private OrderWorkflow(OrderState state) =&gt; State = state;    public static OrderWorkflow Create(string orderId, decimal amount) =&gt;        new(new Drafted(orderId, amount));    public static OrderWorkflow FromState(OrderState state) =&gt; new(state);    public StepResult Next(StepInput input) =&gt; State switch    {        Drafted(var id, var amount) =&gt;            NoInputOnly(input, () =&gt; MoveTo(new Submitted(id, amount))),        Submitted(var id, var amount) =&gt; input switch        {            NoInput =&gt; new AwaitInput(new ApprovalRequest(&amp;quot;Approve submission for review?&amp;quot;)),            ApprovalAnswer(false, _) =&gt; EndWith(new Rejected(id, &amp;quot;Submission not approved for review.&amp;quot;)),            ApprovalAnswer(true, _) when amount &gt; 1000m =&gt; MoveTo(new InReview(id, amount)),            ApprovalAnswer(true, _) =&gt; MoveTo(new Approved(id, amount)),        },        InReview(var id, var amount) =&gt; input switch        {            NoInput =&gt; new AwaitInput(new ManagerApprovalRequest(&amp;quot;Manager approval required.&amp;quot;, amount)),            ApprovalAnswer(false, _) =&gt; EndWith(new Rejected(id, &amp;quot;Manager rejected the order.&amp;quot;)),            ApprovalAnswer(true, _) =&gt; MoveTo(new Approved(id, amount)),        },        Approved(var id, _) =&gt; NoInputOnly(input, () =&gt; EndWith(new Fulfilled(id))),        Rejected =&gt; EndWith(State),        Fulfilled =&gt; EndWith(State),    };    private StepResult MoveTo(OrderState next)    {        State = next;        return new Advance(State);    }    private StepResult EndWith(OrderState terminal)    {        State = terminal;        return new Finish(State);    }    // Steps that don&amp;#x27;t wait for anything reject unexpected input.    private static StepResult NoInputOnly(StepInput input, Func&lt;StepResult&gt; step) =&gt; input switch    {        NoInput =&gt; step(),        ApprovalAnswer =&gt; new Fail(&amp;quot;This step does not take input.&amp;quot;),    };}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Add a new &lt;code&gt;StepInput&lt;/code&gt; case, and every &lt;code&gt;input switch&lt;/code&gt; above lights up with a warning until you handle it. Add a new state, and the outer &lt;code&gt;State&lt;/code&gt; switch warns the same way.&lt;/p&gt;
&lt;h2 id=&quot;driving-the-workflow&quot;&gt;&lt;a href=&quot;#driving-the-workflow&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Driving the Workflow”&quot;&gt;Driving the Workflow&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The caller loops until it gets a &lt;code&gt;Finish&lt;/code&gt; or a &lt;code&gt;Fail&lt;/code&gt;. Notice that the caller answers a request by switching on its type, which is exhaustive too.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;wf&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;answers&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; queue &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Queue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(answers);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; wf.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (result)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; request):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Answer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(request, queue.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Dequeue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// in real life: a person or a webhook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Answer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;approve&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; request &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(approve, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(approve, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Reviewed by manager&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;static StepResult Run(OrderWorkflow wf, bool[] answers){    var queue = new Queue&lt;bool&gt;(answers);    StepInput input = new NoInput();    while (true)    {        var result = wf.Next(input);        switch (result)        {            case Finish:            case Fail:                return result;            case AwaitInput(var request):                input = Answer(request, queue.Dequeue()); // in real life: a person or a webhook                break;            case Advance:                input = new NoInput();                break;        }    }}static StepInput Answer(InputRequest request, bool approve) =&gt; request switch{    ApprovalRequest =&gt; new ApprovalAnswer(approve, null),    ManagerApprovalRequest =&gt; new ApprovalAnswer(approve, &amp;quot;Reviewed by manager&amp;quot;),};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For a $250 order, the workflow walks &lt;code&gt;Drafted → Submitted → Approved → Fulfilled&lt;/code&gt;. For a $9,999 order, it takes a detour through &lt;code&gt;InReview&lt;/code&gt;, and a “no” from the manager lands in &lt;code&gt;Rejected&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;state=InReview(id=order-3, amount=9999) -&amp;gt; AwaitInput(ManagerApprovalRequest: Manager approval required. (9999))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;state=Rejected(id=order-3, reason=Manager rejected the order.) -&amp;gt; Finish(Rejected(id=order-3, reason=Manager rejected the order.))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;state=InReview(id=order-3, amount=9999) -&gt; AwaitInput(ManagerApprovalRequest: Manager approval required. (9999))state=Rejected(id=order-3, reason=Manager rejected the order.) -&gt; Finish(Rejected(id=order-3, reason=Manager rejected the order.))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Sending an answer to a step that isn’t waiting gives you a &lt;code&gt;Fail&lt;/code&gt; rather than an exception:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Fail(This step does not take input.)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Fail(This step does not take input.)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you’ve ever written a C# state machine with an enum and a giant &lt;code&gt;switch&lt;/code&gt;, the difference is that each state brings only the data it needs. A &lt;code&gt;Rejected&lt;/code&gt; state has a reason, and a &lt;code&gt;Drafted&lt;/code&gt; state doesn’t.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-serialize-and-rehydrate-a-union-workflow&quot;&gt;&lt;a href=&quot;#how-do-you-serialize-and-rehydrate-a-union-workflow&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do You Serialize and Rehydrate a Union Workflow?”&quot;&gt;How Do You Serialize and Rehydrate a Union Workflow?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A workflow that can wait for a human is only useful if you can stop the process and pick it up later. That means serializing the current state and rehydrating it.&lt;/p&gt;
&lt;p&gt;Serialize and rehydrate by persisting the &lt;code&gt;State&lt;/code&gt; with an explicit discriminator. By default, &lt;code&gt;System.Text.Json&lt;/code&gt; in .NET 11 serializes a union by writing only the active case’s JSON, so &lt;code&gt;new Submitted(&quot;order-1&quot;, 250m)&lt;/code&gt; becomes &lt;code&gt;{&quot;OrderId&quot;:&quot;order-1&quot;,&quot;Amount&quot;:250}&lt;/code&gt; with no tag. Reading it back works when the cases map to different JSON token types, such as a string and an object. Two object-shaped cases are ambiguous, so &lt;code&gt;Deserialize&amp;lt;OrderState&amp;gt;&lt;/code&gt; throws:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;JsonException: JSON value type &apos;Object&apos; is ambiguous for union type &apos;OrderState&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;because multiple case types can use this value type. Specify a custom type&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;classifier to support deserialization.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;JsonException: JSON value type &amp;#x27;Object&amp;#x27; is ambiguous for union type &amp;#x27;OrderState&amp;#x27;because multiple case types can use this value type. Specify a custom typeclassifier to support deserialization.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For stored workflow state, I don’t want to depend on shape-guessing. (If you’ve handled this for class hierarchies, it’s the same idea as &lt;a href=&quot;https://khalidabuhakmeh.com/polymorphic-serialization-with-dotnet-system-text-json&quot;&gt;polymorphic serialization with System.Text.Json&lt;/a&gt;.) I want an explicit tag that survives refactoring, so the state gets a small converter that wraps each case as &lt;code&gt;{&quot;$case&quot;: &quot;...&quot;, &quot;value&quot;: {...}}&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OrderStateConverter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonConverter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Utf8JsonReader&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;reader&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;typeToConvert&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonSerializerOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; JsonDocument.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ParseValue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; reader);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; kind &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc.RootElement.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc.RootElement.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; kind &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Drafted) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Submitted) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ...one arm per case&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonException&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Unknown OrderState case &apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Utf8JsonWriter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;writer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonSerializerOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteStartObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; d:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Drafted));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, d, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ...one arm per case&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteEndObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public sealed class OrderStateConverter : JsonConverter&lt;OrderState&gt;{    public override OrderState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)    {        using var doc = JsonDocument.ParseValue(ref reader);        var kind = doc.RootElement.GetProperty(&amp;quot;$case&amp;quot;).GetString();        var value = doc.RootElement.GetProperty(&amp;quot;value&amp;quot;);        return kind switch        {            nameof(Drafted) =&gt; (OrderState)value.Deserialize&lt;Drafted&gt;(options)!,            nameof(Submitted) =&gt; (OrderState)value.Deserialize&lt;Submitted&gt;(options)!,            // ...one arm per case            _ =&gt; throw new JsonException($&amp;quot;Unknown OrderState case &amp;#x27;{kind}&amp;#x27;&amp;quot;),        };    }    public override void Write(Utf8JsonWriter writer, OrderState value, JsonSerializerOptions options)    {        writer.WriteStartObject();        switch (value)        {            case Drafted d:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Drafted));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, d, options);                break;            // ...one arm per case        }        writer.WriteEndObject();    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The persisted JSON is small and readable:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;9999&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{&amp;quot;$case&amp;quot;:&amp;quot;InReview&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;OrderId&amp;quot;:&amp;quot;order-2&amp;quot;,&amp;quot;Amount&amp;quot;:9999}}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Rehydrating is one line each way, because the whole workflow is its &lt;code&gt;State&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(wf.State, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;wf &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FromState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(json, options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var json = JsonSerializer.Serialize(wf.State, options);wf = OrderWorkflow.FromState(JsonSerializer.Deserialize&lt;OrderState&gt;(json, options)!);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You don’t need to persist a pending question. After rehydrating a workflow that was waiting, call &lt;code&gt;Next(new NoInput())&lt;/code&gt; and it asks again with the same &lt;code&gt;InputRequest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To prove it works, the complete program at the end of this post serializes after every &lt;code&gt;Next&lt;/code&gt; call, builds a brand-new &lt;code&gt;OrderWorkflow&lt;/code&gt; from the JSON, and keeps driving that copy. It then asserts that the outcome matches an uninterrupted run. That holds for the approved path, the manager-review path, and the rejected path.&lt;/p&gt;
&lt;h2 id=&quot;things-to-watch-for&quot;&gt;&lt;a href=&quot;#things-to-watch-for&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Things to Watch For”&quot;&gt;Things to Watch For&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefer switch expressions.&lt;/strong&gt; Only &lt;code&gt;switch&lt;/code&gt; &lt;em&gt;expressions&lt;/em&gt; get the union exhaustiveness check. A &lt;code&gt;switch&lt;/code&gt; &lt;em&gt;statement&lt;/em&gt; over a union isn’t treated as exhaustive, so a method ending in one fails with CS0161 unless you add a trailing &lt;code&gt;throw&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unions are structs, so &lt;code&gt;default&lt;/code&gt; is a trap.&lt;/strong&gt; &lt;code&gt;default(OrderState).Value&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;. With nullable reference types on, a &lt;code&gt;switch&lt;/code&gt; expression over a union warns CS8655 because &lt;code&gt;null&lt;/code&gt; isn’t covered, and switching on a &lt;code&gt;default&lt;/code&gt; union throws &lt;code&gt;SwitchExpressionException&lt;/code&gt; at run time. Always initialize union fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value-type cases are boxed.&lt;/strong&gt; Everything lives in an &lt;code&gt;object?&lt;/code&gt; &lt;code&gt;Value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;?.&lt;/code&gt; and nullable returns don’t compile on unions.&lt;/strong&gt; You’ll see CS0023 for &lt;code&gt;?.&lt;/code&gt;, and CS0508 if a &lt;code&gt;JsonConverter&amp;lt;OrderState&amp;gt;&lt;/code&gt; override returns &lt;code&gt;OrderState?&lt;/code&gt;. That’s another reason &lt;code&gt;NoInput&lt;/code&gt; beats &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nested unions and overlapping JSON shapes&lt;/strong&gt; aren’t supported by the built-in classifier, per the System.Text.Json docs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It’s a release candidate.&lt;/strong&gt; The “What’s new in C# 15” page still describes C# 15 as preview, while the RC1 release notes say unions are stabilized. Behavior may change before GA.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;&lt;a href=&quot;#where-to-go-from-here&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Where to Go From Here”&quot;&gt;Where to Go From Here&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A few things this post leaves open, if you want to take it further:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Closed hierarchies with &lt;code&gt;[JsonDerivedType]&lt;/code&gt;.&lt;/strong&gt; The docs describe explicit discriminators through &lt;code&gt;[JsonDerivedType(typeof(X), &quot;tag&quot;)]&lt;/code&gt;, and .NET 11 can infer polymorphism from a closed hierarchy. That could replace the hand-written converter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native AOT and source generation.&lt;/strong&gt; I haven’t checked the converter under either.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioning.&lt;/strong&gt; Rename &lt;code&gt;Submitted&lt;/code&gt;, and stored &lt;code&gt;$case&lt;/code&gt; values stop matching. A real system needs a version field or a migration step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-state inputs.&lt;/strong&gt; &lt;code&gt;StepInput&lt;/code&gt; is shared by every step, so a step can still receive an input meant for another and answers with &lt;code&gt;Fail&lt;/code&gt;. Making that impossible needs per-state input types, which means generics or more than one method.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Four small unions and one &lt;code&gt;Next&lt;/code&gt; method cover the whole workflow, and the compiler flags every state, input, and result you forget to handle. The persisted state is a tagged JSON object that rehydrates to the same outcome as an uninterrupted run.&lt;/p&gt;
&lt;p&gt;Next, try replacing the hand-written converter with &lt;code&gt;[JsonDerivedType]&lt;/code&gt; and see how much code you can delete. If it works for your cases, I’d like to hear about it.&lt;/p&gt;
&lt;p&gt;Thanks to the C# language team for shipping this one.&lt;/p&gt;
&lt;h2 id=&quot;complete-program&quot;&gt;&lt;a href=&quot;#complete-program&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Complete Program”&quot;&gt;Complete Program&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s the whole thing in one file. Run &lt;code&gt;dotnet new console&lt;/code&gt; with the .NET 11 SDK, set &lt;code&gt;&amp;lt;LangVersion&amp;gt;15.0&amp;lt;/LangVersion&amp;gt;&lt;/code&gt; in the project file, replace &lt;code&gt;Program.cs&lt;/code&gt; with the code below, and run it. It runs the workflow with and without serialization, then prints the JSON at every step.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Json&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Json&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Serialization&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Demo: run a workflow with and without serialize/rehydrate at every step.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;=== Run A: uninterrupted ===&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; outcomeA &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;250m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;), [&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;rehydrate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;=== Run B: serialize/rehydrate at every step ===&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; outcomeB &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;250m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;), [&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;rehydrate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Run A outcome: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;outcomeA&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Run B outcome: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;outcomeB&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(outcomeA) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(outcomeB))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Mismatch between uninterrupted and rehydrated runs!&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;=== Run C: large order needs manager review (approved) ===&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; outcomeC &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;9999m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;), [&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;rehydrate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Run C outcome: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;outcomeC&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;=== Run D: manager rejects the order ===&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; outcomeD &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;9999m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;), [&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;rehydrate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Run D outcome: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;outcomeD&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(outcomeD).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;StartsWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Finish(Rejected(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Expected a rejected outcome.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;=== Run E: input sent to a step that doesn&apos;t take input ===&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; outcomeE &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order-4&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;50m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Run E outcome: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;outcomeE&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (outcomeE &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Expected Fail.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;ALL ASSERTIONS PASSED.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Helpers&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// The caller drives the workflow. Every AwaitInput carries a typed request, so&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// the caller knows what kind of answer to build.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;wf&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;answers&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;rehydrate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; queue &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Queue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(answers);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; wf.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;  state=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;wf&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (rehydrate)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Serialize the workflow after every Next() call, then keep driving&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// a brand-new instance built from the JSON.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; WorkflowJson.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(wf);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;      json: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; rehydrated &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; WorkflowJson.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(json);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(wf.State) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(rehydrated.State))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Round-trip mismatch!&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;wf &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; rehydrated;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (result)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; request):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Answer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(request, queue.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Dequeue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// The request type decides which answer is valid; the switch is exhaustive.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Answer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;approve&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; request &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(approve, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(approve, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Reviewed by manager&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Describe&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; state) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Advance(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; request) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;AwaitInput(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeRequest&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; state) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Finish(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; reason) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Fail(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;reason&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; question) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;ApprovalRequest: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;question&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; question, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;ManagerApprovalRequest: &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;question&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;DescribeState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Drafted(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, amount=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Submitted(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, amount=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;InReview(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, amount=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Approved(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, amount=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; reason) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rejected(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, reason=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;reason&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Fulfilled(id=&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Union declarations (C# 15 `union` feature)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Naming: states are past tense (what has happened). Results are present-tense&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// instructions to the caller. Inputs and requests are nouns.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// States. Each case carries only the data that state needs.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Reason&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;OrderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What the caller sends in.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Comment&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What a waiting step asks the caller for.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Question&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Question&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What Next() tells the caller to do.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;union&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InputRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Reason&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Workflow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; state;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;orderId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(orderId, amount));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FromState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(state);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// The ONE method. Always returns a StepResult, and takes a typed StepInput.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount))),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Approve submission for review?&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Submission not approved for review.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1000m&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; amount) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AwaitInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ManagerApprovalRequest&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Manager approval required.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Manager rejected the order.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id, amount)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(id))),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; next;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Advance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EndWith&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;terminal&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;State &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; terminal;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Finish&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(State);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Steps that don&apos;t wait for anything reject unexpected input.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NoInputOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;StepResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; input &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NoInput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ApprovalAnswer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fail&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;This step does not take input.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// JSON serialization support&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// =============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// What was tried:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// 1. Default System.Text.Json behavior for a `union`. Serializing writes only the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//    active case&apos;s own JSON (no discriminator), and deserializing throws a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//    JsonException (&quot;ambiguous for union type ... specify a custom type classifier&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//    when more than one case could match the JSON shape.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// 2. An explicit discriminator written by hand: every state is serialized as&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//    { &quot;$case&quot;: &quot;&amp;lt;name&amp;gt;&quot;, &quot;value&quot;: { ... } } via a custom JsonConverter&amp;lt;OrderState&amp;gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//    This is what&apos;s used below.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OrderStateConverter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonConverter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Utf8JsonReader&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;reader&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;typeToConvert&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonSerializerOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; JsonDocument.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ParseValue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; reader);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; root &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc.RootElement;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; kind &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; root.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; root.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; kind &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Drafted) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Submitted) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(InReview) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Approved) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Rejected) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Fulfilled) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonException&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Unknown OrderState case &apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Utf8JsonWriter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;writer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonSerializerOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteStartObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Drafted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; d:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Drafted));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, d, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Submitted&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; s:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Submitted));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, s, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;InReview&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; m:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(InReview));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, m, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Approved&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; a:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Approved));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, a, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rejected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; r:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Rejected));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, r, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Fulfilled&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; c:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$case&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Fulfilled));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WritePropertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(writer, c, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonException&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Unknown OrderState case &apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetType&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteEndObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;WorkflowJson&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;JsonSerializerOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Options &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;WriteIndented &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Converters &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderStateConverter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;wf&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(wf.State, Options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderWorkflow&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; state &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; JsonSerializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OrderState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(json, Options)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; OrderWorkflow.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FromState&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(state);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.Text.Json;using System.Text.Json.Serialization;// ---------------------------------------------------------------------------// Demo: run a workflow with and without serialize/rehydrate at every step.// ---------------------------------------------------------------------------Console.WriteLine(&amp;quot;=== Run A: uninterrupted ===&amp;quot;);var outcomeA = Run(OrderWorkflow.Create(&amp;quot;order-1&amp;quot;, 250m), [true, true], rehydrate: false);Console.WriteLine();Console.WriteLine(&amp;quot;=== Run B: serialize/rehydrate at every step ===&amp;quot;);var outcomeB = Run(OrderWorkflow.Create(&amp;quot;order-1&amp;quot;, 250m), [true, true], rehydrate: true);Console.WriteLine();Console.WriteLine($&amp;quot;Run A outcome: {Describe(outcomeA)}&amp;quot;);Console.WriteLine($&amp;quot;Run B outcome: {Describe(outcomeB)}&amp;quot;);if (Describe(outcomeA) != Describe(outcomeB)){    throw new Exception(&amp;quot;Mismatch between uninterrupted and rehydrated runs!&amp;quot;);}Console.WriteLine();Console.WriteLine(&amp;quot;=== Run C: large order needs manager review (approved) ===&amp;quot;);var outcomeC = Run(OrderWorkflow.Create(&amp;quot;order-2&amp;quot;, 9999m), [true, true], rehydrate: true);Console.WriteLine($&amp;quot;Run C outcome: {Describe(outcomeC)}&amp;quot;);Console.WriteLine();Console.WriteLine(&amp;quot;=== Run D: manager rejects the order ===&amp;quot;);var outcomeD = Run(OrderWorkflow.Create(&amp;quot;order-3&amp;quot;, 9999m), [true, false], rehydrate: true);Console.WriteLine($&amp;quot;Run D outcome: {Describe(outcomeD)}&amp;quot;);if (!Describe(outcomeD).StartsWith(&amp;quot;Finish(Rejected(&amp;quot;)){    throw new Exception(&amp;quot;Expected a rejected outcome.&amp;quot;);}Console.WriteLine();Console.WriteLine(&amp;quot;=== Run E: input sent to a step that doesn&amp;#x27;t take input ===&amp;quot;);var outcomeE = OrderWorkflow.Create(&amp;quot;order-4&amp;quot;, 50m).Next(new ApprovalAnswer(true, null));Console.WriteLine($&amp;quot;Run E outcome: {Describe(outcomeE)}&amp;quot;);if (outcomeE is not Fail){    throw new Exception(&amp;quot;Expected Fail.&amp;quot;);}Console.WriteLine();Console.WriteLine(&amp;quot;ALL ASSERTIONS PASSED.&amp;quot;);// ---------------------------------------------------------------------------// Helpers// ---------------------------------------------------------------------------// The caller drives the workflow. Every AwaitInput carries a typed request, so// the caller knows what kind of answer to build.static StepResult Run(OrderWorkflow wf, bool[] answers, bool rehydrate){    var queue = new Queue&lt;bool&gt;(answers);    StepInput input = new NoInput();    while (true)    {        var result = wf.Next(input);        Console.WriteLine($&amp;quot;  state={DescribeState(wf.State)} -&gt; {Describe(result)}&amp;quot;);        if (rehydrate)        {            // Serialize the workflow after every Next() call, then keep driving            // a brand-new instance built from the JSON.            var json = WorkflowJson.Serialize(wf);            Console.WriteLine($&amp;quot;      json: {json}&amp;quot;);            var rehydrated = WorkflowJson.Deserialize(json);            if (DescribeState(wf.State) != DescribeState(rehydrated.State))            {                throw new Exception(&amp;quot;Round-trip mismatch!&amp;quot;);            }            wf = rehydrated;        }        switch (result)        {            case Finish:            case Fail:                return result;            case AwaitInput(var request):                input = Answer(request, queue.Dequeue());                break;            case Advance:                input = new NoInput();                break;        }    }}// The request type decides which answer is valid; the switch is exhaustive.static StepInput Answer(InputRequest request, bool approve) =&gt; request switch{    ApprovalRequest =&gt; new ApprovalAnswer(approve, null),    ManagerApprovalRequest =&gt; new ApprovalAnswer(approve, &amp;quot;Reviewed by manager&amp;quot;),};static string Describe(StepResult r) =&gt; r switch{    Advance(var state) =&gt; $&amp;quot;Advance({DescribeState(state)})&amp;quot;,    AwaitInput(var request) =&gt; $&amp;quot;AwaitInput({DescribeRequest(request)})&amp;quot;,    Finish(var state) =&gt; $&amp;quot;Finish({DescribeState(state)})&amp;quot;,    Fail(var reason) =&gt; $&amp;quot;Fail({reason})&amp;quot;,};static string DescribeRequest(InputRequest r) =&gt; r switch{    ApprovalRequest(var question) =&gt; $&amp;quot;ApprovalRequest: {question}&amp;quot;,    ManagerApprovalRequest(var question, var amount) =&gt; $&amp;quot;ManagerApprovalRequest: {question} ({amount})&amp;quot;,};static string DescribeState(OrderState s) =&gt; s switch{    Drafted(var id, var amount) =&gt; $&amp;quot;Drafted(id={id}, amount={amount})&amp;quot;,    Submitted(var id, var amount) =&gt; $&amp;quot;Submitted(id={id}, amount={amount})&amp;quot;,    InReview(var id, var amount) =&gt; $&amp;quot;InReview(id={id}, amount={amount})&amp;quot;,    Approved(var id, var amount) =&gt; $&amp;quot;Approved(id={id}, amount={amount})&amp;quot;,    Rejected(var id, var reason) =&gt; $&amp;quot;Rejected(id={id}, reason={reason})&amp;quot;,    Fulfilled(var id) =&gt; $&amp;quot;Fulfilled(id={id})&amp;quot;,};// =============================================================================// Union declarations (C# 15 &amp;#x60;union&amp;#x60; feature)//// Naming: states are past tense (what has happened). Results are present-tense// instructions to the caller. Inputs and requests are nouns.// =============================================================================// States. Each case carries only the data that state needs.public union OrderState(Drafted, Submitted, InReview, Approved, Rejected, Fulfilled);public record Drafted(string OrderId, decimal Amount);public record Submitted(string OrderId, decimal Amount);public record InReview(string OrderId, decimal Amount);public record Approved(string OrderId, decimal Amount);public record Rejected(string OrderId, string Reason);public record Fulfilled(string OrderId);// What the caller sends in.public union StepInput(NoInput, ApprovalAnswer);public record NoInput;public record ApprovalAnswer(bool Approved, string? Comment);// What a waiting step asks the caller for.public union InputRequest(ApprovalRequest, ManagerApprovalRequest);public record ApprovalRequest(string Question);public record ManagerApprovalRequest(string Question, decimal Amount);// What Next() tells the caller to do.public union StepResult(Advance, AwaitInput, Finish, Fail);public record Advance(OrderState State);public record AwaitInput(InputRequest Request);public record Finish(OrderState State);public record Fail(string Reason);// =============================================================================// Workflow// =============================================================================public sealed class OrderWorkflow{    public OrderState State { get; private set; }    private OrderWorkflow(OrderState state) =&gt; State = state;    public static OrderWorkflow Create(string orderId, decimal amount) =&gt;        new(new Drafted(orderId, amount));    public static OrderWorkflow FromState(OrderState state) =&gt; new(state);    // The ONE method. Always returns a StepResult, and takes a typed StepInput.    public StepResult Next(StepInput input) =&gt; State switch    {        Drafted(var id, var amount) =&gt; NoInputOnly(input, () =&gt; MoveTo(new Submitted(id, amount))),        Submitted(var id, var amount) =&gt; input switch        {            NoInput =&gt; new AwaitInput(new ApprovalRequest(&amp;quot;Approve submission for review?&amp;quot;)),            ApprovalAnswer(false, _) =&gt; EndWith(new Rejected(id, &amp;quot;Submission not approved for review.&amp;quot;)),            ApprovalAnswer(true, _) when amount &gt; 1000m =&gt; MoveTo(new InReview(id, amount)),            ApprovalAnswer(true, _) =&gt; MoveTo(new Approved(id, amount)),        },        InReview(var id, var amount) =&gt; input switch        {            NoInput =&gt; new AwaitInput(new ManagerApprovalRequest(&amp;quot;Manager approval required.&amp;quot;, amount)),            ApprovalAnswer(false, _) =&gt; EndWith(new Rejected(id, &amp;quot;Manager rejected the order.&amp;quot;)),            ApprovalAnswer(true, _) =&gt; MoveTo(new Approved(id, amount)),        },        Approved(var id, _) =&gt; NoInputOnly(input, () =&gt; EndWith(new Fulfilled(id))),        Rejected =&gt; EndWith(State),        Fulfilled =&gt; EndWith(State),    };    private StepResult MoveTo(OrderState next)    {        State = next;        return new Advance(State);    }    private StepResult EndWith(OrderState terminal)    {        State = terminal;        return new Finish(State);    }    // Steps that don&amp;#x27;t wait for anything reject unexpected input.    private static StepResult NoInputOnly(StepInput input, Func&lt;StepResult&gt; step) =&gt; input switch    {        NoInput =&gt; step(),        ApprovalAnswer =&gt; new Fail(&amp;quot;This step does not take input.&amp;quot;),    };}// =============================================================================// JSON serialization support// =============================================================================//// What was tried://// 1. Default System.Text.Json behavior for a &amp;#x60;union&amp;#x60;. Serializing writes only the//    active case&amp;#x27;s own JSON (no discriminator), and deserializing throws a//    JsonException (&amp;quot;ambiguous for union type ... specify a custom type classifier&amp;quot;)//    when more than one case could match the JSON shape.//// 2. An explicit discriminator written by hand: every state is serialized as//    { &amp;quot;$case&amp;quot;: &amp;quot;&lt;name&gt;&amp;quot;, &amp;quot;value&amp;quot;: { ... } } via a custom JsonConverter&lt;OrderState&gt;.//    This is what&amp;#x27;s used below.public sealed class OrderStateConverter : JsonConverter&lt;OrderState&gt;{    public override OrderState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)    {        using var doc = JsonDocument.ParseValue(ref reader);        var root = doc.RootElement;        var kind = root.GetProperty(&amp;quot;$case&amp;quot;).GetString();        var value = root.GetProperty(&amp;quot;value&amp;quot;);        return kind switch        {            nameof(Drafted) =&gt; (OrderState)value.Deserialize&lt;Drafted&gt;(options)!,            nameof(Submitted) =&gt; (OrderState)value.Deserialize&lt;Submitted&gt;(options)!,            nameof(InReview) =&gt; (OrderState)value.Deserialize&lt;InReview&gt;(options)!,            nameof(Approved) =&gt; (OrderState)value.Deserialize&lt;Approved&gt;(options)!,            nameof(Rejected) =&gt; (OrderState)value.Deserialize&lt;Rejected&gt;(options)!,            nameof(Fulfilled) =&gt; (OrderState)value.Deserialize&lt;Fulfilled&gt;(options)!,            _ =&gt; throw new JsonException($&amp;quot;Unknown OrderState case &amp;#x27;{kind}&amp;#x27;&amp;quot;),        };    }    public override void Write(Utf8JsonWriter writer, OrderState value, JsonSerializerOptions options)    {        writer.WriteStartObject();        switch (value)        {            case Drafted d:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Drafted));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, d, options);                break;            case Submitted s:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Submitted));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, s, options);                break;            case InReview m:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(InReview));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, m, options);                break;            case Approved a:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Approved));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, a, options);                break;            case Rejected r:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Rejected));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, r, options);                break;            case Fulfilled c:                writer.WriteString(&amp;quot;$case&amp;quot;, nameof(Fulfilled));                writer.WritePropertyName(&amp;quot;value&amp;quot;);                JsonSerializer.Serialize(writer, c, options);                break;            default:                throw new JsonException($&amp;quot;Unknown OrderState case &amp;#x27;{value.GetType()}&amp;#x27;&amp;quot;);        }        writer.WriteEndObject();    }}public static class WorkflowJson{    private static readonly JsonSerializerOptions Options = new()    {        WriteIndented = false,        Converters = { new OrderStateConverter() },    };    public static string Serialize(OrderWorkflow wf) =&gt;        JsonSerializer.Serialize(wf.State, Options);    public static OrderWorkflow Deserialize(string json)    {        var state = JsonSerializer.Deserialize&lt;OrderState&gt;(json, Options)!;        return OrderWorkflow.FromState(state);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;sources&quot;&gt;&lt;a href=&quot;#sources&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Sources”&quot;&gt;Sources&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/union&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Union types (C# reference)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/csharplang/blob/main/proposals/csharp-15.0/unions.md&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;C# 15 unions specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/rc1/csharp.md#c-15-stabilizes-unions-and-other-language-features&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;.NET 11 RC1 C# release notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/union-types&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Serialize union types with System.Text.Json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/polymorphism&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Serialize properties of derived classes (polymorphism)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>dotnet</category><category>csharp</category></item><item><title>Directory.Build.props: Share Settings Across .NET Projects</title><link>https://khalidabuhakmeh.com/posts/directory-build-props-share-settings-across-dotnet-projects/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/directory-build-props-share-settings-across-dotnet-projects/</guid><description>Directory.Build.props shares MSBuild properties like Nullable and LangVersion across every .NET project in a solution, including nested overrides.</description><pubDate>Mon, 12 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;&lt;code&gt;Directory.Build.props&lt;/code&gt;&lt;/strong&gt; is an MSBuild file that sets properties and package references once for every project below it in the folder tree. MSBuild finds it on its own, imports it before the project’s own settings, and lets any &lt;code&gt;.csproj&lt;/code&gt; override a value by setting it again.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project&gt;  &lt;PropertyGroup&gt;    &lt;Nullable&gt;enable&lt;/Nullable&gt;  &lt;/PropertyGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Drop that at the root of your solution, next to the &lt;code&gt;.sln&lt;/code&gt; file, and every project below it gets &lt;code&gt;Nullable&lt;/code&gt; enabled without you touching a single &lt;code&gt;.csproj&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-directorybuildprops-and-how-does-msbuild-find-it&quot;&gt;&lt;a href=&quot;#what-is-directorybuildprops-and-how-does-msbuild-find-it&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is Directory.Build.props and How Does MSBuild Find It?”&quot;&gt;What Is Directory.Build.props and How Does MSBuild Find It?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MSBuild finds the file on its own, with no setup step. The SDK-style project format (&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;Microsoft.NET.Sdk&lt;/code&gt;&lt;/a&gt;) imports a tiny bit of MSBuild logic (&lt;code&gt;Sdk.props&lt;/code&gt;) at the very top of every project, and that logic searches upward from the project’s directory for a file named &lt;code&gt;Directory.Build.props&lt;/code&gt;, stopping at the first one it finds. It does &lt;strong&gt;not&lt;/strong&gt; keep walking further up and merging multiple copies; it imports exactly one.&lt;/p&gt;
&lt;p&gt;Because the import happens near the top of the project file, before your project’s own &lt;code&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/code&gt; elements are evaluated, any property you set later in the &lt;code&gt;.csproj&lt;/code&gt; wins. In my test, a root file set &lt;code&gt;Nullable&lt;/code&gt; to &lt;code&gt;enable&lt;/code&gt; and one project’s &lt;code&gt;.csproj&lt;/code&gt; set it to &lt;code&gt;disable&lt;/code&gt;. That project got &lt;code&gt;disable&lt;/code&gt;, and its siblings kept &lt;code&gt;enable&lt;/code&gt;. Put sensible defaults in the shared file and override them per project when you need to.&lt;/p&gt;
&lt;h2 id=&quot;what-does-a-typical-directorybuildprops-look-like&quot;&gt;&lt;a href=&quot;#what-does-a-typical-directorybuildprops-look-like&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Does a Typical Directory.Build.props Look Like?”&quot;&gt;What Does a Typical Directory.Build.props Look Like?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s one for &lt;code&gt;Directory.Build.props&lt;/code&gt; a solution with a class library, a web API, and a test project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;LangVersion&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;latest&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;LangVersion&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;true&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Authors&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Khalid Abuhakmeh&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Authors&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Company&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Example Co&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Company&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Roslynator.Analyzers&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;5.0.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;all&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project&gt;  &lt;PropertyGroup&gt;    &lt;LangVersion&gt;latest&lt;/LangVersion&gt;    &lt;Nullable&gt;enable&lt;/Nullable&gt;    &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt;    &lt;TreatWarningsAsErrors&gt;true&lt;/TreatWarningsAsErrors&gt;    &lt;Authors&gt;Khalid Abuhakmeh&lt;/Authors&gt;    &lt;Company&gt;Example Co&lt;/Company&gt;  &lt;/PropertyGroup&gt;  &lt;ItemGroup&gt;    &lt;PackageReference Include=&amp;quot;Roslynator.Analyzers&amp;quot; Version=&amp;quot;5.0.1&amp;quot;&gt;      &lt;PrivateAssets&gt;all&lt;/PrivateAssets&gt;      &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/IncludeAssets&gt;    &lt;/PackageReference&gt;  &lt;/ItemGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;After adding this, individual project files shrink down to just what’s actually different per project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.NET.Sdk.Web&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;net10.0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.AspNetCore.OpenApi&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;10.0.12&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project Sdk=&amp;quot;Microsoft.NET.Sdk.Web&amp;quot;&gt;  &lt;PropertyGroup&gt;    &lt;TargetFramework&gt;net10.0&lt;/TargetFramework&gt;  &lt;/PropertyGroup&gt;  &lt;ItemGroup&gt;    &lt;PackageReference Include=&amp;quot;Microsoft.AspNetCore.OpenApi&amp;quot; Version=&amp;quot;10.0.12&amp;quot; /&gt;  &lt;/ItemGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;No more &lt;code&gt;Nullable&lt;/code&gt;, &lt;code&gt;ImplicitUsings&lt;/code&gt;, or &lt;code&gt;Authors&lt;/code&gt; repeated in every project. Running &lt;code&gt;dotnet msbuild -getProperty:Authors&lt;/code&gt; on each project showed all three picking up &lt;code&gt;Khalid Abuhakmeh&lt;/code&gt; from the shared file, and the analyzer reference showed up in all three builds. For the other files that live next to your projects, see &lt;a href=&quot;https://khalidabuhakmeh.com/common-files-dotnet-solution&quot;&gt;common files in a .NET solution&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-happens-when-you-nest-directorybuildprops-files&quot;&gt;&lt;a href=&quot;#what-happens-when-you-nest-directorybuildprops-files&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Happens When You Nest Directory.Build.props Files?”&quot;&gt;What Happens When You Nest Directory.Build.props Files?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The closest file wins and nothing merges. If a subfolder has its own &lt;code&gt;Directory.Build.props&lt;/code&gt;, MSBuild imports that one and never touches the root file.&lt;/p&gt;
&lt;p&gt;To test it, I kept a root file that set &lt;code&gt;Authors&lt;/code&gt; and &lt;code&gt;TreatWarningsAsErrors&lt;/code&gt;, then added a second &lt;code&gt;Directory.Build.props&lt;/code&gt; in one project’s parent folder with a single unrelated property. That project lost both values and fell back to MSBuild defaults, even though the root file sat a few folders up.&lt;/p&gt;
&lt;p&gt;If you want a nested file to extend the root one instead of replacing it, import the parent explicitly:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Import&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$([MSBuild]::GetPathOfFileAbove(&apos;Directory.Build.props&apos;, &apos;$(MSBuildThisFileDirectory)../&apos;))&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- properties specific to this folder --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project&gt;  &lt;Import Project=&amp;quot;$([MSBuild]::GetPathOfFileAbove(&amp;#x27;Directory.Build.props&amp;#x27;, &amp;#x27;$(MSBuildThisFileDirectory)../&amp;#x27;))&amp;quot; /&gt;  &lt;PropertyGroup&gt;    &lt;!-- properties specific to this folder --&gt;  &lt;/PropertyGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With that &lt;code&gt;Import&lt;/code&gt; line in the nested file, &lt;code&gt;-getProperty:Authors&lt;/code&gt; and &lt;code&gt;-getProperty:LangVersion&lt;/code&gt; returned the root values again, alongside the nested folder’s own property. It’s an easy mistake to add a nested file for one subdirectory and silently lose everything from the root.&lt;/p&gt;
&lt;h2 id=&quot;when-should-you-use-directorybuildtargets-instead&quot;&gt;&lt;a href=&quot;#when-should-you-use-directorybuildtargets-instead&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “When Should You Use Directory.Build.targets Instead?”&quot;&gt;When Should You Use Directory.Build.targets Instead?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;Directory.Build.targets&lt;/code&gt; when your logic depends on values the project sets. &lt;code&gt;Directory.Build.props&lt;/code&gt; is imported early, so it can’t see properties the project itself hasn’t set yet, like &lt;code&gt;AssemblyName&lt;/code&gt; or &lt;code&gt;TargetFramework&lt;/code&gt; as finalized by the SDK. If you need logic that reacts to those values, like a custom build target or a property that’s computed from something the project defines, put it in &lt;code&gt;Directory.Build.targets&lt;/code&gt; instead. The SDK imports this file late, after the project body, so everything the project set is already in scope.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Target&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;PrintBuildInfo&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;AfterTargets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Importance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;high&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Building $(MSBuildProjectName) for $(TargetFramework), AssemblyName=$(AssemblyName)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Target&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project&gt;  &lt;Target Name=&amp;quot;PrintBuildInfo&amp;quot; AfterTargets=&amp;quot;Build&amp;quot;&gt;    &lt;Message Importance=&amp;quot;high&amp;quot; Text=&amp;quot;Building $(MSBuildProjectName) for $(TargetFramework), AssemblyName=$(AssemblyName)&amp;quot; /&gt;  &lt;/Target&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With this at the solution root, &lt;code&gt;dotnet build&lt;/code&gt; printed each project’s real &lt;code&gt;TargetFramework&lt;/code&gt; and &lt;code&gt;AssemblyName&lt;/code&gt;, values that only exist after the project file is evaluated. &lt;code&gt;Directory.Build.targets&lt;/code&gt; follows the same search rule as the props file, so a nested one replaces the root one unless you import it explicitly.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-share-package-versions&quot;&gt;&lt;a href=&quot;#how-do-you-share-package-versions&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do You Share Package Versions?”&quot;&gt;How Do You Share Package Versions?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;Directory.Packages.props&lt;/code&gt; for package versions. It’s a separate but related file: &lt;code&gt;Directory.Packages.props&lt;/code&gt;, which enables &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;central package management&lt;/a&gt;. Set &lt;code&gt;ManagePackageVersionsCentrally&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; and list versions once as &lt;code&gt;PackageVersion&lt;/code&gt; items; your project files then reference packages by name only, no &lt;code&gt;Version&lt;/code&gt; attribute.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ManagePackageVersionsCentrally&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;true&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ManagePackageVersionsCentrally&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageVersion&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Roslynator.Analyzers&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;5.0.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project&gt;  &lt;PropertyGroup&gt;    &lt;ManagePackageVersionsCentrally&gt;true&lt;/ManagePackageVersionsCentrally&gt;  &lt;/PropertyGroup&gt;  &lt;ItemGroup&gt;    &lt;PackageVersion Include=&amp;quot;Roslynator.Analyzers&amp;quot; Version=&amp;quot;5.0.1&amp;quot; /&gt;  &lt;/ItemGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Adding this file to my scratch solution immediately produced NuGet error &lt;code&gt;NU1008&lt;/code&gt; on every project that still had an explicit &lt;code&gt;Version&lt;/code&gt; on a &lt;code&gt;PackageReference&lt;/code&gt;. That includes the analyzer reference in the shared &lt;code&gt;Directory.Build.props&lt;/code&gt; above, so remove its &lt;code&gt;Version&lt;/code&gt; attribute once the version lives here. After that the split is simple: &lt;code&gt;Directory.Build.props&lt;/code&gt; for compiler and analyzer settings, &lt;code&gt;Directory.Packages.props&lt;/code&gt; for package versions.&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Imported&lt;/th&gt;
&lt;th&gt;Use it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Directory.Build.props&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Early, before the project body&lt;/td&gt;
&lt;td&gt;Defaults projects can override, like &lt;code&gt;Nullable&lt;/code&gt; or &lt;code&gt;LangVersion&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Directory.Build.targets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Late, after the project body&lt;/td&gt;
&lt;td&gt;Targets and properties that depend on the project’s final values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Directory.Packages.props&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;With central package management enabled&lt;/td&gt;
&lt;td&gt;Package versions, via &lt;code&gt;PackageVersion&lt;/code&gt; items&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;If you publish packages, the shared &lt;code&gt;Authors&lt;/code&gt; value also becomes your package’s author metadata. See &lt;a href=&quot;https://khalidabuhakmeh.com/a-dotnet-five-guide-from-idea-to-nuget-package&quot;&gt;the guide from idea to NuGet package&lt;/a&gt; for the rest of that workflow, and &lt;a href=&quot;https://khalidabuhakmeh.com/using-environment-variables-in-your-dotnet-core-builds&quot;&gt;using environment variables in your .NET builds&lt;/a&gt; for pulling build-time values into properties.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-debug-what-got-imported&quot;&gt;&lt;a href=&quot;#how-do-you-debug-what-got-imported&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do You Debug What Got Imported?”&quot;&gt;How Do You Debug What Got Imported?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two switches save you from guessing. First, ask MSBuild directly what value a property resolved to for a given project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;dotnet msbuild path/to/Project.csproj -getProperty:Nullable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet msbuild path/to/Project.csproj -getProperty:Nullable&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Second, if you want to see the fully expanded project file, with every &lt;code&gt;Import&lt;/code&gt; inlined, including &lt;code&gt;Directory.Build.props&lt;/code&gt; and &lt;code&gt;Directory.Build.targets&lt;/code&gt;, generate a preprocessed copy:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;dotnet msbuild path/to/Project.csproj -pp:out.xml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet msbuild path/to/Project.csproj -pp:out.xml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I ran both against the scratch solution. &lt;code&gt;-getProperty&lt;/code&gt; returned exactly the values each &lt;code&gt;Directory.Build.props&lt;/code&gt; and &lt;code&gt;.csproj&lt;/code&gt; combination should produce, and &lt;code&gt;out.xml&lt;/code&gt; contained the flattened contents of the imported &lt;code&gt;Directory.Build.props&lt;/code&gt; next to the project’s own elements. I tested on the .NET 10 SDK. &lt;code&gt;-getProperty&lt;/code&gt; is a recent MSBuild switch, so on an older SDK check &lt;code&gt;dotnet msbuild -h&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;For a view of the whole build, record a binary log and open it in &lt;a href=&quot;https://github.com/KirillOsenkov/MSBuildStructuredLog&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;MSBuildStructuredLog&lt;/a&gt; (&lt;a href=&quot;https://msbuildlog.com&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;project site&lt;/a&gt;), a free viewer by &lt;a href=&quot;https://osenkov.com&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Kirill Osenkov&lt;/a&gt;. Pass &lt;code&gt;-bl&lt;/code&gt; to &lt;code&gt;dotnet build&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;dotnet build -bl&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet build -bl&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That writes &lt;code&gt;msbuild.binlog&lt;/code&gt; next to your solution. The log records the targets, tasks, and property and item values from the build, and the viewer lets you browse and search them. When a property comes out wrong, you can search the log for the property name and see where it was set, instead of guessing which file won.&lt;/p&gt;
&lt;img src=&quot;https://khalidabuhakmeh.com/assets/images/posts/directory-build-props/msbuild-structured-log-viewer.webp&quot; alt=&quot;MSBuild Structured Log Viewer showing a build tree, search pane, and a project file with line numbers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;1052&quot;&gt;
&lt;p&gt;&lt;em&gt;Screenshot from the MSBuildStructuredLog repository, which is MIT licensed.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-common-gotchas&quot;&gt;&lt;a href=&quot;#what-are-the-common-gotchas&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Are the Common Gotchas?”&quot;&gt;What Are the Common Gotchas?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Four things are easy to forget:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It applies to every project below it, including tests.&lt;/strong&gt; If your test projects live under the same root as your main projects, they inherit everything from &lt;code&gt;Directory.Build.props&lt;/code&gt; too, unless they’re under a nested folder with their own copy of the file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nesting replaces, it doesn’t merge.&lt;/strong&gt; As shown above, a closer &lt;code&gt;Directory.Build.props&lt;/code&gt; means the root one is skipped entirely unless you add the explicit &lt;code&gt;Import&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File name casing matters on case-sensitive file systems.&lt;/strong&gt; Windows and macOS default to case-insensitive file systems, so &lt;code&gt;directory.build.props&lt;/code&gt; and &lt;code&gt;Directory.Build.props&lt;/code&gt; are treated the same. On a case-sensitive Linux file system, the name has to match exactly, &lt;code&gt;Directory.Build.props&lt;/code&gt;, or MSBuild won’t find it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It’s imported before the project body, &lt;code&gt;Directory.Build.targets&lt;/code&gt; after.&lt;/strong&gt; Use &lt;code&gt;.props&lt;/code&gt; for defaults you want projects to be able to override, and &lt;code&gt;.targets&lt;/code&gt; for logic that needs to see the project’s final property values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the full reference on both files and how the SDK wires them in, see the &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;official MSBuild docs on customizing your build&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>dotnet</category><category>msbuild</category></item><item><title>Convert a String to an Int in C#</title><link>https://khalidabuhakmeh.com/posts/convert-a-string-to-an-int-in-csharp/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/convert-a-string-to-an-int-in-csharp/</guid><description>Three reliable ways to convert a string to an int in C# — int.Parse, int.TryParse, and Convert.ToInt32 — plus which one to reach for and why.</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Converting a string to an int in C# is a daily chore, whether the value comes from user input, a query string, a config file, or a CSV. I’ll walk through the three built-in options—int.TryParse, int.Parse, and Convert.ToInt32—and when to reach for each.&lt;/p&gt;
&lt;h2 id=&quot;inttryparse--convert-a-string-safely&quot;&gt;&lt;a href=&quot;#inttryparse--convert-a-string-safely&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “int.TryParse : Convert a String Safely”&quot;&gt;int.TryParse : Convert a String Safely&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When dealing with untrusted input, you’ll want to lean on &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.int32.tryparse&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;int.TryParse&lt;/code&gt;&lt;/a&gt;. The method follows the typical &lt;code&gt;TryX&lt;/code&gt; pattern found in other .NET APIs. On success, the method returns &lt;code&gt;true&lt;/code&gt; and an &lt;code&gt;out&lt;/code&gt; parameter containing the resulting value. On failure, it returns &lt;code&gt;false&lt;/code&gt; and sets the &lt;code&gt;out&lt;/code&gt; parameter to &lt;code&gt;0&lt;/code&gt;. This makes it easy to handle both success and failure cases without exceptions. Always branch on the &lt;code&gt;bool&lt;/code&gt; return value, though: a failed parse leaves &lt;code&gt;number&lt;/code&gt; at &lt;code&gt;0&lt;/code&gt;, which is indistinguishable from successfully parsing &lt;code&gt;&quot;0&quot;&lt;/code&gt;, so never infer success from the &lt;code&gt;out&lt;/code&gt; value alone. It’s the same approach I reach for when &lt;a href=&quot;https://khalidabuhakmeh.com/read-and-convert-querycollection-values-in-aspnet&quot;&gt;reading and converting QueryCollection values in ASP.NET&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryParse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; number))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// success — use `number`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// failure — `number` is 0 here, but 0 is also a valid parse of &quot;0&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// so always check the bool, never the out value alone&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if (int.TryParse(input, out int number)){    // success — use &amp;#x60;number&amp;#x60;}else{    // failure — &amp;#x60;number&amp;#x60; is 0 here, but 0 is also a valid parse of &amp;quot;0&amp;quot;,    // so always check the bool, never the out value alone}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;int.TryParse&lt;/code&gt; is the best option for most developers when converting strings to integers, especially when the input may not be guaranteed to be valid.&lt;/p&gt;
&lt;h2 id=&quot;intparse--simple-but-it-throws&quot;&gt;&lt;a href=&quot;#intparse--simple-but-it-throws&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “int.Parse : Simple, but It Throws”&quot;&gt;int.Parse : Simple, but It Throws&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When working with trusted input, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.int32.parse&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;int.Parse&lt;/code&gt;&lt;/a&gt; is your most straightforward option. Since you’re a developer either controlling the input or guaranteeing its format through strict validation, you can use &lt;code&gt;int.Parse&lt;/code&gt; without worrying about exceptions (even though you should always worry about exceptions). Although, there are some edge cases as you can see in the example below.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Parse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// number == 42&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// int.Parse(&quot;4a2&quot;)  -&amp;gt; throws FormatException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// int.Parse(null)   -&amp;gt; throws ArgumentNullException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// int.Parse(&quot;9999999999&quot;) -&amp;gt; throws OverflowException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;int number = int.Parse(&amp;quot;42&amp;quot;);// number == 42// int.Parse(&amp;quot;4a2&amp;quot;)  -&gt; throws FormatException// int.Parse(null)   -&gt; throws ArgumentNullException// int.Parse(&amp;quot;9999999999&amp;quot;) -&gt; throws OverflowException&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;int.Parse&lt;/code&gt; for quick prototypes and code samples for non-production code.&lt;/p&gt;
&lt;h2 id=&quot;converttoint32--the-null-tolerant-option&quot;&gt;&lt;a href=&quot;#converttoint32--the-null-tolerant-option&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Convert.ToInt32 : The Null-Tolerant Option”&quot;&gt;Convert.ToInt32 : The Null-Tolerant Option&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may be tempted to use the &lt;code&gt;Convert&lt;/code&gt; class and its &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.convert.toint32&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;Convert.ToInt32&lt;/code&gt;&lt;/a&gt; method. The key difference between the other approaches is this method treats &lt;code&gt;null&lt;/code&gt; as &lt;code&gt;0&lt;/code&gt; instead of throwing an exception. This can be useful in scenarios where a missing value should be interpreted as zero, but it can also lead to unexpected outcomes and bugs that will make you pull your hair out.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Convert.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToInt32&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// 42&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; b &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Convert.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToInt32&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// 0  (no exception!)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Convert.ToInt32(&quot;4a2&quot;)        -&amp;gt; throws FormatException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;int a = Convert.ToInt32(&amp;quot;42&amp;quot;);   // 42int b = Convert.ToInt32(null);   // 0  (no exception!)// Convert.ToInt32(&amp;quot;4a2&amp;quot;)        -&gt; throws FormatException&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Leave this method in the toolbox and favor the other two approaches for more predictable behavior.&lt;/p&gt;
&lt;h2 id=&quot;why-does-string-to-int-parsing-fail&quot;&gt;&lt;a href=&quot;#why-does-string-to-int-parsing-fail&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Why Does String-to-Int Parsing Fail?”&quot;&gt;Why Does String-to-Int Parsing Fail?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Outside of parsing strings into integers, the biggest pain point you need to watch for is culture and format. By default, parsing uses the current culture and &lt;code&gt;NumberStyles.Integer&lt;/code&gt;, which allows for a leading sign and surrounding whitespace only. This means that strings like &lt;code&gt;&quot;1,304&quot;&lt;/code&gt; will fail unless you explicitly allow thousands separators and provide a culture. The .NET docs on &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/base-types/parsing-numeric&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;parsing numeric strings&lt;/a&gt; cover the full set of &lt;code&gt;NumberStyles&lt;/code&gt; rules.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;NumberStyles&lt;/code&gt; and &lt;code&gt;CultureInfo&lt;/code&gt; to handle these cases properly. For example, the following code demonstrates how to parse a string with a thousands separator:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Globalization&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryParse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1,304&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; fails);          &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// false -&amp;gt; 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryParse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1,304&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;NumberStyles.Integer &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; NumberStyles.AllowThousands,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;CultureInfo.InvariantCulture,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; works);                             &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// true  -&amp;gt; 1304&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.Globalization;int.TryParse(&amp;quot;1,304&amp;quot;, out var fails);          // false -&gt; 0int.TryParse(&amp;quot;1,304&amp;quot;,    NumberStyles.Integer | NumberStyles.AllowThousands,    CultureInfo.InvariantCulture,    out var works);                             // true  -&gt; 1304&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you’re hoping to deploy your code into multiple regions or region agnostic environments, consider using &lt;code&gt;CultureInfo.InvariantCulture&lt;/code&gt; to ensure consistent parsing behavior across different locales. Culture sneaks into more string work than you’d expect—I ran into it again while &lt;a href=&quot;https://khalidabuhakmeh.com/writing-a-string-numeric-comparer-with-dotnet-9&quot;&gt;writing a string numeric comparer with .NET 9&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;which-should-you-use&quot;&gt;&lt;a href=&quot;#which-should-you-use&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Which Should You Use?”&quot;&gt;Which Should You Use?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So given your options, which of these should you use? From personal experience, use &lt;code&gt;int.TryParse&lt;/code&gt; by default. It is the safest and most efficient option for handling untrusted input, and it avoids exceptions that can disrupt your application’s flow. Use &lt;code&gt;int.Parse&lt;/code&gt; only when you are certain the input is valid, and reserve &lt;code&gt;Convert.ToInt32&lt;/code&gt; for cases where you want to treat &lt;code&gt;null&lt;/code&gt; as &lt;code&gt;0&lt;/code&gt;. Just remember to always consider the culture and format of the input string to avoid unexpected parsing issues.&lt;/p&gt;
&lt;p&gt;Here is a quick reference for which method to use based on your input scenario:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input Scenario&lt;/th&gt;
&lt;th&gt;Recommended Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Untrusted input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int.TryParse&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trusted / guaranteed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int.Parse&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need &lt;code&gt;null&lt;/code&gt; to mean &lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Convert.ToInt32&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Thanks for reading! If you found this post helpful, you might also enjoy &lt;a href=&quot;https://khalidabuhakmeh.com/convert-a-csharp-object-to-almost-any-format&quot;&gt;converting a C# object to almost any format&lt;/a&gt; and my other posts on C# and .NET development.&lt;/p&gt;
</content:encoded><category>dotnet</category><category>csharp</category><category>tips</category></item><item><title>Rails to ASP.NET Core: A Developer&apos;s Map</title><link>https://khalidabuhakmeh.com/posts/rails-developers-map-to-dotnet/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/rails-developers-map-to-dotnet/</guid><description>Map Rails conventions, Hotwire, Active Record, and Sidekiq to ASP.NET Core, EF Core, htmx, Blazor, Hangfire, and more.</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;While it feels like many software developers have picked their bread and butter frameworks these days, there are still opportunities to explore other technologies and ecosystems. What makes adoption difficult is fighting our muscle memory and looking for familiar signposts. Our experience can be both our biggest advantage and disadvantage when moving between stacks.&lt;/p&gt;
&lt;p&gt;This guide maps Rails conventions, Action Pack, Hotwire, Active Record, Sidekiq, and the Rails CLI to their closest ASP.NET Core and .NET counterparts. It began as an answer to a Reddit user’s question and is a conceptual map rather than a migration guide.&lt;/p&gt;
&lt;p&gt;It is for full-stack Rails developers and API-focused Rails developers who want to expand their technical toolbox, evaluate .NET for a future project, or simply see how the other side lives.&lt;/p&gt;
&lt;h2 id=&quot;how-do-rails-and-aspnet-core-handle-convention-over-configuration&quot;&gt;&lt;a href=&quot;#how-do-rails-and-aspnet-core-handle-convention-over-configuration&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do Rails and ASP.NET Core Handle Convention Over Configuration?”&quot;&gt;How Do Rails and ASP.NET Core Handle Convention Over Configuration?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Convention over configuration reduces ceremony by making predictable choices on a team’s behalf. Rails is strongly opinionated: its default directory layout, naming rules, ORM conventions, generators, and integrated components guide most applications toward a familiar shape. That consistency makes it easy to move between Rails projects and quickly recognize where code belongs.&lt;/p&gt;
&lt;p&gt;ASP.NET Core also has opinions, but they are more loosely held. Think of it as “opinions lite.” Its templates provide conventional layouts, dependency injection, configuration, logging, routing, and framework-specific patterns such as MVC controllers or Razor Pages. Unlike Rails, however, ASP.NET Core expects you to compose the pieces you need and readily permits multiple valid approaches to the same problem.&lt;/p&gt;
&lt;p&gt;For a Rails developer, this is the important adjustment: ASP.NET Core MVC will feel familiar because it has controllers, views, routing, conventions, and validation. But the framework will ask you to make more decisions about project structure, data access, background processing, and UI architecture. That flexibility is useful when a project needs it, but it also means teams should agree on their conventions early.&lt;/p&gt;
&lt;h2 id=&quot;how-does-rubys-dynamic-typing-compare-to-c&quot;&gt;&lt;a href=&quot;#how-does-rubys-dynamic-typing-compare-to-c&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Does Ruby’s Dynamic Typing Compare to C#?”&quot;&gt;How Does Ruby’s Dynamic Typing Compare to C#?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The biggest difference Ruby developers will notice in .NET is C#’s static type system. Neither approach is inherently better, but they move feedback to different points in the development cycle. Ruby gives you flexibility at runtime and leans heavily on tests to verify an object’s shape and behavior. C# asks you to declare those shapes up front and lets the compiler catch many mismatches before the application runs.&lt;/p&gt;
&lt;p&gt;In daily work, that means renaming a property or changing a method signature in C# usually produces a list of compiler errors that points to every affected caller. You will also encounter nullable reference types, which let the compiler warn when code might use a missing value. Tests are still essential in .NET, but the compiler becomes an additional quality gate alongside them.&lt;/p&gt;
&lt;p&gt;Rails developers will most often model application concepts with classes or records, then use interfaces when they need to describe a contract independent of a particular implementation. At the edges of an application, it is common to use explicit request and response models instead of passing database entities directly between controllers, views, APIs, and persistence. This can initially feel more verbose than Ruby, but it makes those boundaries and their expected data clearer to both the compiler and the next developer reading the code.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-aspnet-core-equivalent-of-action-pack&quot;&gt;&lt;a href=&quot;#what-is-the-aspnet-core-equivalent-of-action-pack&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is the ASP.NET Core Equivalent of Action Pack?”&quot;&gt;What Is the ASP.NET Core Equivalent of Action Pack?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rails’ core web framework system is called Action Pack. It provides the familiar request pipeline: routing accepts an incoming request, selects a controller action, binds input, and renders a response.&lt;/p&gt;
&lt;p&gt;ASP.NET Core has multiple web frameworks built on its endpoint routing system. MVC, Razor Pages, Minimal APIs, and Blazor all use the same hosting, configuration, dependency injection, middleware, logging, and routing foundations. The programming model you select determines how you organize endpoints and render a response.&lt;/p&gt;
&lt;p&gt;For a Rails developer looking for the closest mental model, start with &lt;strong&gt;ASP.NET Core MVC&lt;/strong&gt;. The concepts will feel familiar:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails&lt;/th&gt;
&lt;th&gt;ASP.NET Core MVC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;config/routes.rb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Endpoint route configuration in &lt;code&gt;Program.cs&lt;/code&gt; and route attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controller action&lt;/td&gt;
&lt;td&gt;Controller action method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action Controller filters&lt;/td&gt;
&lt;td&gt;Middleware, endpoint filters, and MVC filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong parameters&lt;/td&gt;
&lt;td&gt;Input models, model binding, and validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action View template&lt;/td&gt;
&lt;td&gt;Razor view&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The models are analogous, not identical. Rails supplies stronger defaults around its application structure, while ASP.NET Core gives teams more latitude to decide how routes, services, data access, and features are organized.&lt;/p&gt;
&lt;p&gt;Other ASP.NET Core programming models are appropriate in specific situations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Razor Pages&lt;/strong&gt; is a good fit for page-centric, server-rendered applications, especially CRUD screens. A Razor Page keeps a page’s markup and its request-handling code together, but it does not replace your domain or persistence models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal APIs&lt;/strong&gt; work well for small HTTP services, focused endpoint groups, and teams that prefer endpoint-first code without controllers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blazor&lt;/strong&gt; is a component framework for interactive .NET user interfaces. It is a different model from Rails’ controller-and-template workflow and deserves consideration when your team wants to build UI components in C#.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start with the &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;ASP.NET Core fundamentals&lt;/a&gt;, then build the &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;official MVC tutorial&lt;/a&gt; or review the &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/razor-pages/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Razor Pages introduction&lt;/a&gt;. When you want to study working applications instead of another tutorial, &lt;a href=&quot;https://github.com/quozd/awesome-dotnet&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Awesome .NET&lt;/a&gt; provides a broad index of .NET projects. For focused ASP.NET Core examples, &lt;a href=&quot;https://github.com/dodyg/practical-aspnetcore&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Practical ASP.NET Core&lt;/a&gt; has runnable samples covering MVC, Razor Pages, Minimal APIs, htmx, authentication, and hosted services.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-net-equivalent-of-action-view-and-hotwire&quot;&gt;&lt;a href=&quot;#what-is-the-net-equivalent-of-action-view-and-hotwire&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is the .NET Equivalent of Action View and Hotwire?”&quot;&gt;What Is the .NET Equivalent of Action View and Hotwire?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The UI layer is where Rails developers are most likely to encounter overwhelming choice. You can continue building server-rendered HTML, use a small amount of JavaScript to update parts of a page, or adopt a fully interactive component model. ASP.NET Core supports each approach, but it does not prescribe a single default in the way Rails does. Again, “opinions lite” as opposed to Rails strong opinions.&lt;/p&gt;
&lt;p&gt;Razor is ASP.NET Core’s server-side HTML templating syntax and is the closest counterpart to Action View. Razor views and Razor Pages render HTML on the server. For reusable pieces of UI, use partial views, View Components, or tag helpers, depending on whether the UI needs only markup, needs to run server-side code, or benefits from HTML-oriented conventions.&lt;/p&gt;
&lt;p&gt;If your Rails team likes Hotwire and Turbo, htmx is worth evaluating. Both approaches keep the server responsible for rendering HTML and let the browser replace targeted portions of a page instead of requiring a JSON API and a client-side framework. They are similar, not interchangeable: Turbo provides its own conventions around navigation, frames, and streams, while htmx uses declarative HTML attributes to issue requests and swap returned HTML into a target.&lt;/p&gt;
&lt;p&gt;I maintain &lt;a href=&quot;https://aspnet-htmx.com/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;HTMX.NET&lt;/a&gt;, an optional ASP.NET Core enhancement library that helps integrate htmx with server-side code. Start with the &lt;a href=&quot;https://htmx.org/docs/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;official htmx documentation&lt;/a&gt;, then see this site’s introductions to &lt;a href=&quot;https://khalidabuhakmeh.com/htmx-with-aspnet-core&quot;&gt;htmx with ASP.NET Core&lt;/a&gt;, &lt;a href=&quot;https://khalidabuhakmeh.com/htmx-and-aspnet-core-swapping-techniques&quot;&gt;htmx swapping techniques&lt;/a&gt;, and &lt;a href=&quot;https://khalidabuhakmeh.com/htmx-requests-with-aspnet-core-anti-forgery-tokens&quot;&gt;anti-forgery tokens in htmx requests&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your team prefers a React-like component model but wants to build components in C#, ASP.NET Core ships with &lt;a href=&quot;https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Blazor&lt;/a&gt;. Blazor supports static server-side rendering plus interactive server, WebAssembly, and auto render modes. It is a different architectural choice from controller-and-template applications, so choose it when stateful, reusable, interactive components are a primary part of the user experience rather than as a direct substitute for Turbo.&lt;/p&gt;
&lt;p&gt;You can also combine these approaches where it makes sense. For example, &lt;a href=&quot;https://khalidabuhakmeh.com/how-to-use-blazor-server-rendered-components-with-htmx&quot;&gt;Blazor server-rendered components can work with htmx&lt;/a&gt; when you want reusable components without committing every part of the UI to a single client interaction model.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-aspnet-core-equivalent-of-rails-api-mode&quot;&gt;&lt;a href=&quot;#what-is-the-aspnet-core-equivalent-of-rails-api-mode&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is the ASP.NET Core Equivalent of Rails API Mode?”&quot;&gt;What Is the ASP.NET Core Equivalent of Rails API Mode?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’re a Rails developer primarily building an API for a frontend, mobile client, or another service, ASP.NET Core offers two primary approaches: API controllers and Minimal APIs. Both use the same routing, model binding, validation, authentication, authorization, dependency injection, and JSON serialization features. The difference is primarily in how your application organizes endpoints.&lt;/p&gt;
&lt;p&gt;Choose &lt;strong&gt;API controllers&lt;/strong&gt; for larger APIs that benefit from established conventions, shared filters, and a familiar class-and-action structure. Choose &lt;strong&gt;Minimal APIs&lt;/strong&gt; for smaller services, focused endpoint groups, or teams that prefer defining an endpoint close to the code that handles it. Neither approach is more capable by default; the right choice is the one your team can keep consistent as the application grows.&lt;/p&gt;
&lt;p&gt;Here is a practical translation of common Rails API concepts:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails API mode&lt;/th&gt;
&lt;th&gt;ASP.NET Core&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;config/routes.rb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Endpoint route configuration in &lt;code&gt;Program.cs&lt;/code&gt;, route groups, or controller route attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controller action&lt;/td&gt;
&lt;td&gt;Controller action or Minimal API route handler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong parameters&lt;/td&gt;
&lt;td&gt;Request models, model binding, and validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;render json:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returning a result or typed response serialized as JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;before_action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Middleware, endpoint filters, MVC filters, and authorization policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jbuilder or serializers&lt;/td&gt;
&lt;td&gt;Response DTOs, anonymous projections, or dedicated serialization types&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Avoid returning Entity Framework Core entities directly from API endpoints. Instead, accept request DTOs and return response DTOs or projections that describe the public API contract. This prevents database implementation details, navigation properties, and accidental fields from leaking into responses while giving you room to change persistence without breaking clients. For deeper Minimal API patterns, see &lt;a href=&quot;https://khalidabuhakmeh.com/aspnet-core-minimal-api-endpoint-filters&quot;&gt;endpoint filters in ASP.NET Core&lt;/a&gt; and &lt;a href=&quot;https://khalidabuhakmeh.com/generating-bogus-http-endpoints-with-aspnet-core-minimal-apis&quot;&gt;generating HTTP endpoints with Minimal APIs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The official &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-9.0&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;ASP.NET Core Web API documentation&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-9.0&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Minimal APIs quick reference&lt;/a&gt; cover the framework features in detail.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-net-equivalent-of-active-record&quot;&gt;&lt;a href=&quot;#what-is-the-net-equivalent-of-active-record&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is the .NET Equivalent of Active Record?”&quot;&gt;What Is the .NET Equivalent of Active Record?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rails developers typically use Active Record, an object-relational mapper built around conventions and active record objects. Entity Framework Core serves a similar purpose in .NET: it maps .NET objects to relational data, tracks changes, manages relationships, and supports schema migrations. The two tools solve many of the same problems, but they organize persistence differently.&lt;/p&gt;
&lt;p&gt;The important distinction is that EF Core generally follows a Data Mapper style. Instead of putting persistence methods directly on a &lt;code&gt;Post&lt;/code&gt; object, you use a &lt;code&gt;DbContext&lt;/code&gt; to query and save entity instances. The &lt;code&gt;DbContext&lt;/code&gt; represents a session with the database, tracks changes to loaded entities, and coordinates &lt;code&gt;SaveChanges&lt;/code&gt; calls. This can feel less magical than Active Record, but it makes the data-access boundary more explicit.&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails&lt;/th&gt;
&lt;th&gt;Entity Framework Core&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Active Record model&lt;/td&gt;
&lt;td&gt;Entity class plus &lt;code&gt;DbContext&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rails db:migrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet ef database update&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration files&lt;/td&gt;
&lt;td&gt;EF Core migrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Associations&lt;/td&gt;
&lt;td&gt;Navigation properties and relationship configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scopes&lt;/td&gt;
&lt;td&gt;LINQ queries, extension methods, or query objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callbacks&lt;/td&gt;
&lt;td&gt;Explicit application/domain logic or EF Core interceptors when appropriate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;LINQ is EF Core’s query language. Many LINQ expressions are translated to SQL and executed by the database, but not every .NET method can be translated. Learn to inspect generated SQL and project only the fields an endpoint needs. When loading relationships, be deliberate about eager loading with &lt;code&gt;Include&lt;/code&gt;, projections, or separate queries so you do not introduce an N+1 query problem. For hands-on follow-up, see &lt;a href=&quot;https://khalidabuhakmeh.com/how-to-use-entity-framework-core-in-aspnet-core&quot;&gt;using Entity Framework Core in ASP.NET Core&lt;/a&gt; and &lt;a href=&quot;https://khalidabuhakmeh.com/add-ef-core-migrations-to-dotnet-aspire-solutions&quot;&gt;adding EF Core migrations to .NET Aspire solutions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/ef/core/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;EF Core documentation&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;EF Core migrations documentation&lt;/a&gt; cover the underlying concepts and commands.&lt;/p&gt;
&lt;h2 id=&quot;how-do-rails-generators-and-bundler-map-to-net&quot;&gt;&lt;a href=&quot;#how-do-rails-generators-and-bundler-map-to-net&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Do Rails Generators and Bundler Map to .NET?”&quot;&gt;How Do Rails Generators and Bundler Map to .NET?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rails has a famously cohesive command-line experience, particularly around generators and project conventions. The .NET CLI is strong at creating projects, building, testing, running, publishing, managing packages, and invoking tools, but it is less generator-centric. You will find scaffolding templates and third-party generators, but they are not as central to the day-to-day .NET workflow as &lt;code&gt;rails generate&lt;/code&gt; is to Rails.&lt;/p&gt;
&lt;p&gt;An uncomfortable truth for command-line-first Rails developers is that .NET developers often prefer IDE or editor tooling for discovery, refactoring, debugging, scaffolding, and project management. JetBrains Rider, Visual Studio, and Visual Studio Code with the C# Dev Kit are common parts of the workflow. You can build and ship entirely from the terminal, but the broader ecosystem often assumes you have capable editor tooling available, which may feel like a cultural adjustment when moving between the two communities.&lt;/p&gt;
&lt;p&gt;Here are the most useful command-line translations:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails&lt;/th&gt;
&lt;th&gt;.NET&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rails new&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet new&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bundle add&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet add package&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bundle exec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet tool run&lt;/code&gt; or a direct &lt;code&gt;dotnet&lt;/code&gt; command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rails db:migrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet ef database update&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rails test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet test&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rails server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dotnet run&lt;/code&gt; or &lt;code&gt;dotnet watch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;NuGet is the closest equivalent to RubyGems, but a &lt;code&gt;.csproj&lt;/code&gt; file generally holds package references rather than a separate Gemfile. Larger .NET solutions may also use Central Package Management to declare package versions in one &lt;code&gt;Directory.Packages.props&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Learn more in the official documentation for &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;the .NET CLI&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/install-use-packages-dotnet-cli&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;NuGet package management&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-net-equivalent-of-activejob-and-sidekiq&quot;&gt;&lt;a href=&quot;#what-is-the-net-equivalent-of-activejob-and-sidekiq&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Is the .NET Equivalent of ActiveJob and Sidekiq?”&quot;&gt;What Is the .NET Equivalent of ActiveJob and Sidekiq?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Background work is essential whenever an operation should outlive an HTTP request: sending email, processing uploaded files, generating reports, or synchronizing with another service. Rails developers commonly use ActiveJob as an abstraction and Sidekiq as a durable job processor. .NET has no single built-in ActiveJob equivalent, so applications usually target a chosen job library directly or define an application-specific abstraction around it.&lt;/p&gt;
&lt;p&gt;The right .NET choice depends on whether the work must survive process restarts and whether you are primarily queueing work or scheduling it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-9.0&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;BackgroundService&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; is built into ASP.NET Core and works well for continuous, in-process work such as polling a source, consuming an already-durable queue, or running a periodic task. By itself, it does not provide Sidekiq-like durable job storage, retries, or a dashboard. Treat it as part of your application process, not as a reliable replacement for a job queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.hangfire.io/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Hangfire&lt;/a&gt;&lt;/strong&gt; is the closest of these options to a Sidekiq-style job system. It persists background jobs in supported storage, supports retries and recurring jobs, and includes a dashboard. It is a strong choice when application code needs to enqueue durable work and monitor it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.quartz-scheduler.net/documentation/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;Quartz.NET&lt;/a&gt;&lt;/strong&gt; is primarily a scheduler. It is well suited for recurring and calendar-based work, and can persist schedules and jobs when configured with durable storage. Use it when scheduling is the central problem rather than general-purpose background job processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For work that must not be lost, use durable storage or a message broker and design for retries, idempotency, observability, and failure handling. An in-memory queue or a fire-and-forget task can disappear when an application restarts or scales out.&lt;/p&gt;
&lt;h2 id=&quot;how-does-the-net-open-source-ecosystem-compare-to-rubygems&quot;&gt;&lt;a href=&quot;#how-does-the-net-open-source-ecosystem-compare-to-rubygems&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “How Does the .NET Open-Source Ecosystem Compare to RubyGems?”&quot;&gt;How Does the .NET Open-Source Ecosystem Compare to RubyGems?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rails developers are accustomed to a deep ecosystem of gems, where reaching for a well-known community package is a normal part of building an application. The .NET ecosystem has a different center of gravity. ASP.NET Core and .NET include many capabilities that Rails developers might otherwise expect to add through gems: dependency injection, configuration, logging, authentication and authorization primitives, background hosted services, caching, HTTP clients, health checks, and structured JSON serialization.&lt;/p&gt;
&lt;p&gt;This means you may need fewer third-party packages to get an application running, but it also changes where you look when you need a capability. Start with the .NET and ASP.NET Core documentation to understand what is already available, then search NuGet for a package when the platform does not meet your requirements.&lt;/p&gt;
&lt;p&gt;The open-source ecosystem is active, but it is less centralized around a small set of universally adopted gems. You will find excellent projects, commercial products, Microsoft-supported packages, and multiple competing options for common problems. Evaluate them the same way you would a Ruby gem: check maintenance activity, issue response, release cadence, documentation, security posture, licensing, and whether the project fits your deployment model.&lt;/p&gt;
&lt;p&gt;The practical adjustment for Rails developers is not that .NET lacks open source. It is that the platform itself covers more of the common web-application baseline, while third-party choices are often more fragmented and problem-specific.&lt;/p&gt;
&lt;h2 id=&quot;rails-to-net-cheat-sheet&quot;&gt;&lt;a href=&quot;#rails-to-net-cheat-sheet&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Rails to .NET Cheat Sheet”&quot;&gt;Rails to .NET Cheat Sheet&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails&lt;/th&gt;
&lt;th&gt;Closest .NET counterpart&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action Pack&lt;/td&gt;
&lt;td&gt;ASP.NET Core MVC or Razor Pages&lt;/td&gt;
&lt;td&gt;MVC is the closest controller-and-view analogue.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action View&lt;/td&gt;
&lt;td&gt;Razor&lt;/td&gt;
&lt;td&gt;Partial views, View Components, and tag helpers compose reusable UI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hotwire/Turbo&lt;/td&gt;
&lt;td&gt;htmx&lt;/td&gt;
&lt;td&gt;Both favor server-rendered HTML; their navigation and update models differ.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active Record&lt;/td&gt;
&lt;td&gt;Entity Framework Core&lt;/td&gt;
&lt;td&gt;EF Core uses &lt;code&gt;DbContext&lt;/code&gt; and LINQ rather than persistence methods on each model.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ActiveJob/Sidekiq&lt;/td&gt;
&lt;td&gt;Hangfire, Quartz.NET, or &lt;code&gt;BackgroundService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Choose durable storage for jobs that must survive restarts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails CLI/Bundler&lt;/td&gt;
&lt;td&gt;.NET CLI/NuGet&lt;/td&gt;
&lt;td&gt;.NET relies more heavily on editor and IDE tooling.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rails and .NET share more ideas than their languages and communities suggest at a cursory glance. Rails offers a strongly opinionated path from a new application to a working product. ASP.NET Core offers familiar web-development building blocks with more opportunities for a team to decide how those blocks fit together.&lt;/p&gt;
&lt;p&gt;If you want to try the .NET ecosystem, start small: create an ASP.NET Core MVC or Razor Pages application, build one CRUD feature with EF Core migrations, and choose htmx or Blazor only when the user experience calls for it. That exercise will show you where the frameworks overlap, where their tradeoffs differ, and which conventions your team needs to establish.&lt;/p&gt;
&lt;p&gt;This map is a starting point, not a migration checklist. It began with a question on &lt;a href=&quot;https://www.reddit.com/r/dotnet/comments/1wxvwl4/can_you_give_me_some_examples/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;r/dotnet asking for Rails equivalents&lt;/a&gt;, and I hope it gives Rails developers enough context to explore .NET with fewer surprises. Bring the Rails practices that serve your team well, learn the .NET platform conventions, and make intentional choices where ASP.NET Core leaves room for them.&lt;/p&gt;
</content:encoded><category>dotnet</category><category>aspnet</category><category>entity-framework</category></item><item><title>Server-Sent Events in ASP.NET Core and .NET 10</title><link>https://khalidabuhakmeh.com/posts/server-sent-events-in-aspnet-core-and-dotnet-10/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/server-sent-events-in-aspnet-core-and-dotnet-10/</guid><description>Build a real-time food-ordering feed in ASP.NET Core Minimal APIs using .NET 10&apos;s TypedResults.ServerSentEvents and an IAsyncEnumerable background service.</description><pubDate>Tue, 22 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;the-anatomy-of-a-sse-endpoint&quot;&gt;&lt;a href=&quot;#the-anatomy-of-a-sse-endpoint&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Anatomy of a SSE Endpoint”&quot;&gt;The Anatomy of a SSE Endpoint&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ComponentModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Runtime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CompilerServices&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; WebApplication.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddSingleton&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;FoodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddHostedService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;FoodServiceWorker&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; app &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseDefaultFiles&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseStaticFiles&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/orders&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;FoodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;foods&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CancellationToken&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;TypedResults.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ServerSentEvents&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;foods.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetCurrent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(token),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;eventType&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.ComponentModel;using System.Runtime.CompilerServices;var builder = WebApplication.CreateBuilder(args);builder.Services.AddSingleton&lt;FoodService&gt;();builder.Services.AddHostedService&lt;FoodServiceWorker&gt;();var app = builder.Build();app.UseDefaultFiles().UseStaticFiles();app.MapGet(&amp;quot;/orders&amp;quot;, (FoodService foods, CancellationToken token) =&gt;    TypedResults.ServerSentEvents(        foods.GetCurrent(token),        eventType: &amp;quot;order&amp;quot;));app.Run();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#implementing-an-iasyncenumerable-food-service&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Implementing an IAsyncEnumerable Food Service”&quot;&gt;Implementing an IAsyncEnumerable Food Service&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;FoodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;INotifyPropertyChanged&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FoodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Current &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Foods[Random.Shared.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Foods.Length)];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? PropertyChanged;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] Foods &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🍔&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🍟&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🥤&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🍤&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🍕&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🌮&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;🥙&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Current&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;field &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnPropertyChanged&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IAsyncEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetCurrent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;EnumeratorCancellation&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CancellationToken&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;ct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (ct &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { IsCancellationRequested: &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; tcs &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TaskCompletionSource&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; handler &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; tcs.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;PropertyChanged &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; handler;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;try&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; tcs.Task.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WaitAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ct);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;finally&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;PropertyChanged &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;-=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; handler;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Current &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Foods[Random.Shared.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Foods.Length)];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnPropertyChanged&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CallerMemberName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;propertyName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Invoke&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(propertyName));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class FoodService : INotifyPropertyChanged{    public FoodService()    {        Current = Foods[Random.Shared.Next(Foods.Length)];    }    public event PropertyChangedEventHandler? PropertyChanged;    private static readonly string[] Foods = [&amp;quot;🍔&amp;quot;, &amp;quot;🍟&amp;quot;, &amp;quot;🥤&amp;quot;, &amp;quot;🍤&amp;quot;, &amp;quot;🍕&amp;quot;, &amp;quot;🌮&amp;quot;, &amp;quot;🥙&amp;quot;];    private string Current    {        get;        set        {            field = value;            OnPropertyChanged();        }    }    public async IAsyncEnumerable&lt;string&gt; GetCurrent(        [EnumeratorCancellation] CancellationToken ct)    {        while (ct is not { IsCancellationRequested: true })        {            yield return Current;            var tcs = new TaskCompletionSource();            PropertyChangedEventHandler handler = (_, _) =&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));    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, I need a background service that updates the food choices at a timed interval.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;FoodServiceWorker&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;FoodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;foodService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;BackgroundService&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ExecuteAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CancellationToken&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;stoppingToken&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;stoppingToken.IsCancellationRequested)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;foodService.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Task.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Delay&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, stoppingToken);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class FoodServiceWorker(FoodService foodService)    : BackgroundService{    protected override async Task ExecuteAsync(CancellationToken stoppingToken)    {        while (!stoppingToken.IsCancellationRequested)        {            foodService.Set();            await Task.Delay(1000, stoppingToken);        }    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#subscribing-to-sse-using-javascript&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Subscribing to SSE using JavaScript”&quot;&gt;Subscribing to SSE using JavaScript&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;en&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;UTF-8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Title&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;flex-direction&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;row&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;list-style&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;flex-wrap&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;wrap&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;90&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;gap&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Khalid&apos;s Fast-Food Fair&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;orders&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; eventSource &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6;--0fw:bold&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;EventSource&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/orders&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; angelsList &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;orders&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;eventSource.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;order&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; li &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;li.textContent &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; event.data;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;angelsList.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;appendChild&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(li);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;eventSource.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;onerror&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;EventSource failed:&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, error);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;eventSource.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;close&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!DOCTYPE html&gt;&lt;html lang=&amp;quot;en&amp;quot;&gt;&lt;head&gt;    &lt;meta charset=&amp;quot;UTF-8&amp;quot;&gt;    &lt;title&gt;Title&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Khalid&amp;#x27;s Fast-Food Fair&lt;/h1&gt;&lt;ul id=&amp;quot;orders&amp;quot;&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;
</content:encoded><category>dotnet</category><category>aspnet</category></item><item><title>Generic C# Methods with Enum Constraints for .NET</title><link>https://khalidabuhakmeh.com/posts/generic-csharp-methods-with-enum-constraints-for-dotnet/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/generic-csharp-methods-with-enum-constraints-for-dotnet/</guid><description>Write a reusable C# generic method that reads enum metadata via reflection while using constraints to stop callers from passing non-enum arguments.</description><pubDate>Tue, 04 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;straight-to-the-implementation&quot;&gt;&lt;a href=&quot;#straight-to-the-implementation&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Straight To The Implementation”&quot;&gt;Straight To The Implementation&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ComponentModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Reflection&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// get all descriptions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Groceries:&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; descriptions &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Enums.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescriptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Groceries&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value, description) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; descriptions)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; - &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Get a description for a single value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value, description) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Enums.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescription&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Groceries.Fruit);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Single value:&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; - &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Groceries&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Apples, Oranges, Bananas&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Fruit,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Spinach, Kale, Broccoli, Cabbage&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Vegetables,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Cheese, Milk, Yogurt&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Dairy,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Chicken, Beef, Pork, Lamb, Turkey&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Meat,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Anything not listed above&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Other&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Enums&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Value, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Description)&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescriptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; values &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Enum.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetValues&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; values)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescription&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Value, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Description) &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescription&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; type &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; info &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; type.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetMember&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(name)[&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; description &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; info.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetCustomAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DescriptionAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { } attr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; attr.Description&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; name;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value, description);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.ComponentModel;using System.Reflection;// get all descriptions{    Console.WriteLine(&amp;quot;Groceries:\n&amp;quot;);    var descriptions = Enums.GetDescriptions&lt;Groceries&gt;();    foreach (var (value, description) in descriptions)    {        Console.WriteLine($&amp;quot;{value} - {description}&amp;quot;);    }    Console.WriteLine();}// Get a description for a single value{    var (value, description) = Enums.GetDescription(Groceries.Fruit);    Console.WriteLine($&amp;quot;Single value:\n{value} - {description}&amp;quot;);}public enum Groceries{    [Description(&amp;quot;Apples, Oranges, Bananas&amp;quot;)]    Fruit,    [Description(&amp;quot;Spinach, Kale, Broccoli, Cabbage&amp;quot;)]    Vegetables,    [Description(&amp;quot;Cheese, Milk, Yogurt&amp;quot;)]    Dairy,    [Description(&amp;quot;Chicken, Beef, Pork, Lamb, Turkey&amp;quot;)]    Meat,    [Description(&amp;quot;Anything not listed above&amp;quot;)]    Other}public static class Enums{    public static IEnumerable&lt;(TEnum Value, string Description)&gt; GetDescriptions&lt;TEnum&gt;()        where TEnum : struct, Enum    {        var values = Enum.GetValues&lt;TEnum&gt;();        foreach (var value in values)        {            yield return GetDescription(value);        }    }    public static (TEnum Value, string Description) GetDescription&lt;TEnum&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&lt;DescriptionAttribute&gt;() is { } attr            ? attr.Description            : name;        return (value, description);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The helper code is here for people who don’t want to visualize the previous sample.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Enums&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Value, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Description)&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescriptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; values &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Enum.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetValues&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; values)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescription&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Value, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Description) &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetDescription&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; type &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TEnum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; info &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; type.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetMember&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(name)[&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; description &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; info.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetCustomAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DescriptionAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { } attr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; attr.Description&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; name;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (value, description);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public static class Enums{    public static IEnumerable&lt;(TEnum Value, string Description)&gt; GetDescriptions&lt;TEnum&gt;()        where TEnum : struct, Enum    {        var values = Enum.GetValues&lt;TEnum&gt;();        foreach (var value in values)        {            yield return GetDescription(value);        }    }    public static (TEnum Value, string Description) GetDescription&lt;TEnum&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&lt;DescriptionAttribute&gt;() is { } attr            ? attr.Description            : name;        return (value, description);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;where TEnum: struct, Enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;where TEnum: struct, Enum&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>dotnet</category><category>csharp</category></item><item><title>Strongly-Typed Markdown for ASP.NET Core Content Apps</title><link>https://khalidabuhakmeh.com/posts/strongly-typed-markdown-for-aspnet-core-content-apps/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/strongly-typed-markdown-for-aspnet-core-content-apps/</guid><description>Build a generic MarkdownObject&lt;T&gt; class with Markdig and YamlDotNet to parse YAML frontmatter into strongly-typed C# models for ASP.NET Core content apps.</description><pubDate>Tue, 25 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;the-magnificent-markdown&quot;&gt;&lt;a href=&quot;#the-magnificent-markdown&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Magnificent Markdown”&quot;&gt;The Magnificent Markdown&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.markdownguide.org/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Khalid Abuhakmeh&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;profession&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Software Developer&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;hobbies&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;video games&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;movies&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;boxing&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BD93F9;--0fw:bold&quot;&gt;## Summary&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;I am writing a little about myself here and this should appear&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;in the page. Cool! Check me out at my [&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;personal blog&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0td:underline&quot;&gt;https://khalidabuhakmeh.com&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---name: &amp;quot;Khalid Abuhakmeh&amp;quot;profession: &amp;quot;Software Developer&amp;quot;hobbies: [&amp;quot;video games&amp;quot;, &amp;quot;movies&amp;quot;, &amp;quot;boxing&amp;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).&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Asset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Name { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Profession { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] Hobbies { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class Asset{    public string Name { get; set; } = &amp;quot;&amp;quot;;    public string Profession { get; set; } = &amp;quot;&amp;quot;;    public string[] Hobbies { get; set; } = [];}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#the-markdownobject-and-parsing-files&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The MarkdownObject and Parsing Files”&quot;&gt;The MarkdownObject and Parsing Files&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Markdig&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;0.40.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;YamlDotNet&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;16.3.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;ItemGroup&gt;  &lt;PackageReference Include=&amp;quot;Markdig&amp;quot; Version=&amp;quot;0.40.0&amp;quot; /&gt;  &lt;PackageReference Include=&amp;quot;YamlDotNet&amp;quot; Version=&amp;quot;16.3.0&amp;quot; /&gt;&lt;/ItemGroup&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s look at the implementation next.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Markdig&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Markdig&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Extensions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Yaml&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Markdig&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Syntax&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;YamlDotNet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Serialization&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Md&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Markdig&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Markdown&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SuperContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;MarkdownObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MarkdownPipeline&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; MarkdownPipeline&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MarkdownPipelineBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseYamlFrontMatter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseAdvancedExtensions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IDeserializer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Deserializer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DeserializerBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WithYamlFormatter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;YamlFormatter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WithCaseInsensitivePropertyMatching&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MarkdownObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; doc &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Md.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Parse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(content, MarkdownPipeline);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;FrontMatter &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (doc.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Descendants&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;YamlFrontMatterBlock&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;FirstOrDefault&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { } fm)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; yaml &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; fm.Lines.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToSlice&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;FrontMatter &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Deserializer.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(yaml.Text);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// we don&apos;t want front matter after it&apos;s processed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;doc.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Remove&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(fm);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// turn it into HTML once&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Html &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(doc.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToHtml&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? FrontMatter { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IHtmlContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Html { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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&lt;T&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&lt;YamlFrontMatterBlock&gt;().FirstOrDefault() is { } fm)        {            var yaml = fm.Lines.ToSlice();            FrontMatter = Deserializer.Deserialize&lt;T&gt;(yaml.Text);            // we don&amp;#x27;t want front matter after it&amp;#x27;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; }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#markdownobject-in-a-razor-page&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “MarkdownObject in a Razor Page”&quot;&gt;MarkdownObject in a Razor Page&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/profile/{slug}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@model&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SuperContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Pages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Profile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;row&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-12&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Asset.FrontMatter?.Name&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;row&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Profession&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Asset.FrontMatter?.Profession&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Hobbies&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (Model.Asset &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { FrontMatter.Hobbies : { } hobbies })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hobby &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hobbies)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;hobby&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-9&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Asset.Html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@page &amp;quot;/profile/{slug}&amp;quot;@model SuperContent.Pages.Profile&lt;div class=&amp;quot;row&amp;quot;&gt;    &lt;div class=&amp;quot;col-12&amp;quot;&gt;        &lt;h1&gt;@Model.Asset.FrontMatter?.Name&lt;/h1&gt;    &lt;/div&gt;&lt;/div&gt;&lt;div class=&amp;quot;row&amp;quot;&gt;    &lt;div class=&amp;quot;col-3&amp;quot;&gt;        &lt;dl&gt;            &lt;dt&gt;Profession&lt;/dt&gt;            &lt;dd&gt;@Model.Asset.FrontMatter?.Profession&lt;/dd&gt;            &lt;dt&gt;Hobbies&lt;/dt&gt;            &lt;dd&gt;                &lt;ul&gt;                    @if (Model.Asset is { FrontMatter.Hobbies : { } hobbies })                    {                        @foreach (var hobby in hobbies)                        {                            &lt;li&gt;@hobby&lt;/li&gt;                        }                    }                &lt;/ul&gt;            &lt;/dd&gt;        &lt;/dl&gt;    &lt;/div&gt;    &lt;div class=&amp;quot;col-9&amp;quot;&gt;        @Model.Asset.Html    &lt;/div&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So, what does the page’s model look like?&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;RegularExpressions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;RazorPages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SuperContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SuperContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Pages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Profile&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PageModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;BindProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(SupportsGet &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Slug { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MarkdownObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Asset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; Asset { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// read a file from the Data directory based on the slug&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// sanitize the slug first because people are mean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; sanitizedSlug &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; SlugRegex.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Replace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Slug, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Path.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Combine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;sanitizedSlug&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.md&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (System.IO.File.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Exists&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(path))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; content &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; System.IO.File.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ReadAllText&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Data/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;sanitizedSlug&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.md&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Asset &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(content);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Page&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;NotFound&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;GeneratedRegex&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;[^a-zA-Z0-9_-]&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Regex&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; SlugRegex { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Asset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Name { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Profession { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] Hobbies { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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; } = &amp;quot;&amp;quot;;    public MarkdownObject&lt;Asset&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, &amp;quot;&amp;quot;);        var path = Path.Combine(&amp;quot;Data&amp;quot;, $&amp;quot;{sanitizedSlug}.md&amp;quot;);        if (System.IO.File.Exists(path))        {            var content = System.IO.File.ReadAllText($&amp;quot;Data/{sanitizedSlug}.md&amp;quot;);            Asset = new(content);            return Page();        }        return NotFound();    }    [GeneratedRegex(&amp;quot;[^a-zA-Z0-9_-]&amp;quot;)]    private static partial Regex SlugRegex { get; }}public class Asset{    public string Name { get; set; } = &amp;quot;&amp;quot;;    public string Profession { get; set; } = &amp;quot;&amp;quot;;    public string[] Hobbies { get; set; } = [];}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;
</content:encoded><category>aspnet</category><category>markdown</category></item><item><title>ConcurrentDictionary GetOrAdd and Closures in .NET</title><link>https://khalidabuhakmeh.com/posts/the-curious-case-of-dotnet-concurrentdictionary-and-closures/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/the-curious-case-of-dotnet-concurrentdictionary-and-closures/</guid><description>Understand why .NET&apos;s ConcurrentDictionary GetOrAdd creates hidden closures and allocations, and how to use the overload that avoids them entirely.</description><pubDate>Tue, 18 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If &lt;code&gt;ConcurrentDictionary.GetOrAdd&lt;/code&gt; is quietly allocating a closure every time you call it, your IDE is probably already nagging you about it. I was recently looking at the &lt;a href=&quot;https://duendesoftware.com&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;what-are-closures&quot;&gt;&lt;a href=&quot;#what-are-closures&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What Are Closures?”&quot;&gt;What Are Closures?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SayHello&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hello &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// name is captured causing an allocation&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// and potential concurrency issues&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;void SayHello(string name){    var hello = () =&gt;    {        // name is captured causing an allocation        // and potential concurrency issues        Console.WriteLine($&amp;quot;Hello {name}&amp;quot;);    };    hello();}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SayHello&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hello &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(name);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;void SayHello(string name){    var hello = (string n) =&gt;    {        Console.WriteLine($&amp;quot;Hello {n}&amp;quot;);    };    hello(name);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#concurrentdictionarygetoradd-and-closure-creation&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “ConcurrentDictionary.GetOrAdd and Closure Creation”&quot;&gt;ConcurrentDictionary.GetOrAdd and Closure Creation&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Collections&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Concurrent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ConcurrentDictionary&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, Item&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; concurrentDictionary&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;khalid&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;awesome&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; concurrentDictionary.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetOrAdd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(key, (&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;k&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Building &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;k&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(value, DateTime.Now);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(result);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.Collections.Concurrent;ConcurrentDictionary&lt;string, Item&gt; concurrentDictionary    = new();var key = &amp;quot;khalid&amp;quot;;var value = &amp;quot;awesome&amp;quot;;var result = concurrentDictionary.GetOrAdd(key, (k) =&gt; {    Console.WriteLine($&amp;quot;Building {k}&amp;quot;);    return new Item(value, DateTime.Now);});Console.WriteLine(result);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Closure can be eliminated: method has overload&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;to avoid closure creation.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Closure can be eliminated: method has overloadto avoid closure creation.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Collections&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Concurrent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ConcurrentDictionary&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; concurrentDictionary &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;khalid&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;awesome&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; concurrentDictionary.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetOrAdd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: key,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;valueFactory&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;k&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;arg&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Building &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;k&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(arg, DateTime.Now);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;factoryArgument&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(result);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Time&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.Collections.Concurrent;ConcurrentDictionary&lt;string, Item&gt; concurrentDictionary = new();var key = &amp;quot;khalid&amp;quot;;var value = &amp;quot;awesome&amp;quot;;var result = concurrentDictionary.GetOrAdd(    key: key,    valueFactory: (k, arg) =&gt;    {        Console.WriteLine($&amp;quot;Building {k}&amp;quot;);        return new Item(arg, DateTime.Now);    },    factoryArgument: value);Console.WriteLine(result);record Item(string Value, DateTime Time);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;
</content:encoded><category>dotnet</category><category>csharp</category></item><item><title>ASP.NET Core and Chunking HTTP Cookies</title><link>https://khalidabuhakmeh.com/posts/aspnet-core-and-chunking-http-cookies/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/aspnet-core-and-chunking-http-cookies/</guid><description>Learn how ASP.NET Core&apos;s ChunkingCookieManager splits oversized HTTP cookies into smaller pieces, helping you work around the 4KB browser cookie limit.</description><pubDate>Tue, 11 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;why-you-would-and-wouldnt-use-cookies&quot;&gt;&lt;a href=&quot;#why-you-would-and-wouldnt-use-cookies&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Why You Would and Wouldn’t Use Cookies”&quot;&gt;Why You Would and Wouldn’t Use Cookies&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;&lt;a href=&quot;#setting-cookies-in-aspnet-core&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Setting Cookies in ASP.NET Core”&quot;&gt;Setting Cookies in ASP.NET Core&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;You can see the &lt;a href=&quot;https://github.com/khalidabuhakmeh/CookieMonster&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ctx.Response.Cookies.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Append&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;cookie_monster&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;nom nom nom&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ctx.Response.Cookies.Append(&amp;quot;cookie_monster&amp;quot;, &amp;quot;nom nom nom&amp;quot;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In our sample, we’ll be reading and rewriting a value with appended data.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/nom-nom&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ctx.Response.Cookies.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Append&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;cookie_monster&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ctx.Request.Cookies.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryGetValue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;cookie_monster&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; cookie)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;cookie&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RandomString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RandomString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// more code&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;app.MapGet(&amp;quot;/nom-nom&amp;quot;, async ctx =&gt;{    ctx.Response.Cookies.Append(&amp;quot;cookie_monster&amp;quot;,        ctx.Request.Cookies.TryGetValue(&amp;quot;cookie_monster&amp;quot;, out var cookie)            ? $&amp;quot;{cookie}, {RandomString()}&amp;quot;            : $&amp;quot;{RandomString()}&amp;quot;);    // more code}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddScoped&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ICookieManager&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;svc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ChunkingCookieManager&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// characters, not bytes... 🤔&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ChunkSize &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, ThrowForPartialCookies &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;builder.Services.AddScoped&lt;ICookieManager&gt;(svc =&gt; new ChunkingCookieManager{    // characters, not bytes... 🤔    ChunkSize = 1000, ThrowForPartialCookies = true});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/chunks&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HttpContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ICookieManager&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;cookieManager&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; cookieManager.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetRequestCookie&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ctx, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;chunky_monster&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { } cookie&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;cookie&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RandomString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RandomString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;cookieManager.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AppendResponseCookie&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ctx, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;chunky_monster&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, value, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CookieOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// more code...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{app.MapGet(&amp;quot;/chunks&amp;quot;, async (HttpContext ctx, ICookieManager cookieManager) =&gt;{    var value = cookieManager.GetRequestCookie(ctx, &amp;quot;chunky_monster&amp;quot;) is { } cookie        ? $&amp;quot;{cookie}, {RandomString()}&amp;quot;        : $&amp;quot;{RandomString()}&amp;quot;;    cookieManager.AppendResponseCookie(ctx, &amp;quot;chunky_monster&amp;quot;, value, new CookieOptions());    // more code...});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;table-wrapper&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Scrollable table&quot;&gt;&lt;table data-wrapped&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;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;
</content:encoded><category>aspnet</category><category>http</category></item><item><title>Vogen and Value Objects with C# and .NET</title><link>https://khalidabuhakmeh.com/posts/vogen-and-value-objects-with-csharp-and-dotnet/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/vogen-and-value-objects-with-csharp-and-dotnet/</guid><description>Vogen is a C# source generator that creates strongly-typed value objects, cutting boilerplate and preventing primitive-obsession bugs.</description><pubDate>Tue, 04 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&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;p&gt;&lt;strong&gt;Vogen is a C# source generator that creates strongly-typed, validated value objects from primitive types, so you get compile-time safety without hand-writing boilerplate wrapper classes.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-value-object&quot;&gt;&lt;a href=&quot;#what-is-a-value-object&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What is a Value Object?”&quot;&gt;What is a Value Object?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; birthDate &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1990&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;DateTime birthDate = new DateTime(1990, 1, 1);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; birthDate &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1990&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetMovieReleaseDate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(birthDate);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetMovieReleaseDate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) { }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;DateTime birthDate = new DateTime(1990, 1, 1);SetMovieReleaseDate(birthDate);void SetMovieReleaseDate(DateTime date) { }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; birthDate &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;BirthDateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1990&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; movieReleaseDate &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MovieReleaseDateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(birthDate.Value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetMovieReleaseDate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(movieReleaseDate);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetMovieReleaseDate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MovieReleaseDateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) { }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// value objects&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;MovieReleaseDateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;BirthDateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#what-is-vogen&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What is Vogen?”&quot;&gt;What is Vogen?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://stevedunn.github.io/Vogen/overview.html&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Vogen&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;7.0.0-beta.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;PackageReference Include=&amp;quot;Vogen&amp;quot; Version=&amp;quot;7.0.0-beta.1&amp;quot; /&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;PacMan&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; FavoriteGhost { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pac Man&apos;s favorite ghost is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;FavoriteGhost&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class PacMan{    public Ghost FavoriteGhost { get; set; }    public override string ToString()    {        return $&amp;quot;Pac Man&amp;#x27;s favorite ghost is {FavoriteGhost}.&amp;quot;;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ValueObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Blinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Blinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Inky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Inky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Clyde&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Clyde&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[ValueObject&lt;string&gt;][Instance(&amp;quot;Blinky&amp;quot;, &amp;quot;Blinky&amp;quot;)][Instance(&amp;quot;Pinky&amp;quot;, &amp;quot;Pinky&amp;quot;)][Instance(&amp;quot;Inky&amp;quot;, &amp;quot;Inky&amp;quot;)][Instance(&amp;quot;Clyde&amp;quot;, &amp;quot;Clyde&amp;quot;)]public partial struct Ghost;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; aNewGhost &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Ghost.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;From&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Khalid&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var aNewGhost = Ghost.From(&amp;quot;Khalid&amp;quot;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ValueObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Blinky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Blinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Pinky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Inky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Inky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Clyde &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Clyde&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IReadOnlyCollection&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; All { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] { Blinky, Pinky, Inky, Clyde }.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AsReadOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Validation&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Validate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;All.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; g.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Equals&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Validation.Ok&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Validation.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Invalid&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Ghost must be &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Join&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;All&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[ValueObject&lt;string&gt;]public partial struct Ghost{    public static readonly Ghost Blinky = new(&amp;quot;Blinky&amp;quot;);    public static readonly Ghost Pinky = new(&amp;quot;Pinky&amp;quot;);    public static readonly Ghost Inky = new(&amp;quot;Inky&amp;quot;);    public static readonly Ghost Clyde = new(&amp;quot;Clyde&amp;quot;);    public static IReadOnlyCollection&lt;Ghost&gt; All { get; }        = new[] { Blinky, Pinky, Inky, Clyde }.AsReadOnly();    private static Validation Validate(string input) =&gt;        All.Any(g =&gt; g.Equals(input))            ? Validation.Ok            : Validation.Invalid($&amp;quot;Ghost must be {string.Join(&amp;quot;, &amp;quot;, All)}&amp;quot;);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// will throw an exception&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; aNewGhost &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Ghost.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;From&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Khalid&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// will pass&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; aKnownGhost &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Ghost.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;From&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Blinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// will throw an exceptionvar aNewGhost = Ghost.From(&amp;quot;Khalid&amp;quot;);// will passvar aKnownGhost = Ghost.From(&amp;quot;Blinky&amp;quot;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s see the use of Vogen in a complete C# sample.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Vogen&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; pacMan &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PacMan&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;FavoriteGhost &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Ghost.Blinky&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ghost &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Ghost.All)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ghost);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(pacMan);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ValueObject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Blinky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Blinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Pinky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pinky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Inky &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Inky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Clyde &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Clyde&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IReadOnlyCollection&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; All { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] { Blinky, Pinky, Inky, Clyde }.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AsReadOnly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Validation&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Validate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;All.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; g.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Equals&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(input))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Validation.Ok&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Validation.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Invalid&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Ghost must be &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Join&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;All&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;PacMan&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Ghost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; FavoriteGhost { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Pac Man&apos;s favorite ghost is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;FavoriteGhost&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using Vogen;var pacMan = new PacMan{    FavoriteGhost = Ghost.Blinky};foreach (var ghost in Ghost.All){    Console.WriteLine(ghost);}Console.WriteLine(pacMan);[ValueObject&lt;string&gt;]public partial struct Ghost{    public static readonly Ghost Blinky = new(&amp;quot;Blinky&amp;quot;);    public static readonly Ghost Pinky = new(&amp;quot;Pinky&amp;quot;);    public static readonly Ghost Inky = new(&amp;quot;Inky&amp;quot;);    public static readonly Ghost Clyde = new(&amp;quot;Clyde&amp;quot;);    public static IReadOnlyCollection&lt;Ghost&gt; All { get; }        = new[] { Blinky, Pinky, Inky, Clyde }.AsReadOnly();    private static Validation Validate(string input) =&gt;        All.Any(g =&gt; g.Equals(input))            ? Validation.Ok            : Validation.Invalid($&amp;quot;Ghost must be {string.Join(&amp;quot;, &amp;quot;, All)}&amp;quot;);}public class PacMan{    public Ghost FavoriteGhost { get; set; }    public override string ToString()    {        return $&amp;quot;Pac Man&amp;#x27;s favorite ghost is {FavoriteGhost}.&amp;quot;;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>csharp</category></item><item><title>Initialize ASP.NET Core TagHelpers with Shared Data</title><link>https://khalidabuhakmeh.com/posts/initialize-aspnet-core-taghelpers-with-shared-data/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/initialize-aspnet-core-taghelpers-with-shared-data/</guid><description>Use the tag helpers infrastructure to initialize all tag helpers of a type</description><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;the-taghelper-in-question&quot;&gt;&lt;a href=&quot;#the-taghelper-in-question&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The TagHelper In Question”&quot;&gt;The TagHelper In Question&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Razor&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rendering&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Razor&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelpers&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;WebApplication2&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlTargetElement&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;MyTagHelper&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelper&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlAttributeName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Text { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlAttributeNotBound&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Version { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ProcessAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelperContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelperOutput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Content.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetHtmlContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Text);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Attributes.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;data-version&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, Version);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Task.CompletedTask;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using Microsoft.AspNetCore.Mvc.Razor;using Microsoft.AspNetCore.Mvc.Rendering;using Microsoft.AspNetCore.Razor.TagHelpers;namespace WebApplication2.Models;[HtmlTargetElement(&amp;quot;span&amp;quot;)]public class MyTagHelper: TagHelper{    [HtmlAttributeName(&amp;quot;text&amp;quot;)]    public string Text { get; set; } = &amp;quot;&amp;quot;;    [HtmlAttributeNotBound]    public string Version { get; set; } = &amp;quot;&amp;quot;;    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)    {        output.Content.SetHtmlContent(Text);        output.Attributes.Add(&amp;quot;data-version&amp;quot;, Version);        return Task.CompletedTask;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Usage of this tag helper is straightforward. In a Razor view, add the following tag.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;fs-1 d-block&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello, World!&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;fs-1 d-block&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;span class=&amp;quot;fs-1 d-block&amp;quot; text=&amp;quot;Hello, World!&amp;quot;&gt;...&lt;/span&gt;&lt;span class=&amp;quot;fs-1 d-block&amp;quot;&gt;&lt;/span&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#taghelper-initializers&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “TagHelper Initializers”&quot;&gt;TagHelper Initializers&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;MyTagHelperInitializer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;defaultText&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ITagHelperInitializer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MyTagHelper&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Initialize&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MyTagHelper&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;helper&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ViewContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;helper.Text &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; defaultText;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;helper.Version &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; version;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class MyTagHelperInitializer(string defaultText, string version)    : ITagHelperInitializer&lt;MyTagHelper&gt;{    public void Initialize(MyTagHelper helper, ViewContext context)    {        helper.Text = defaultText;        helper.Version = version;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.AddSingleton&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ITagHelperInitializer&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MyTagHelper&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MyTagHelperInitializer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Default Text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.0.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;builder.Services.AddSingleton&lt;    ITagHelperInitializer&lt;MyTagHelper&gt;&gt;(new MyTagHelperInitializer(&amp;quot;Default Text&amp;quot;, &amp;quot;1.0.0&amp;quot;));&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;fs-1 d-block&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;data-version&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.0.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Hello, World!&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;fs-1 d-block&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;data-version&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.0.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Default Text&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;span class=&amp;quot;fs-1 d-block&amp;quot; data-version=&amp;quot;1.0.0&amp;quot;&gt;Hello, World!&lt;/span&gt;&lt;span class=&amp;quot;fs-1 d-block&amp;quot; data-version=&amp;quot;1.0.0&amp;quot;&gt;Default Text&lt;/span&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Wow, so easy!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>aspnet</category></item><item><title>Writing a String Numeric Comparer with .NET 9</title><link>https://khalidabuhakmeh.com/posts/writing-a-string-numeric-comparer-with-dotnet-9/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/writing-a-string-numeric-comparer-with-dotnet-9/</guid><description>Write a custom NumericOrderer using .NET 9 Spans to correctly sort strings containing embedded numbers, like movie sequels and version numbers.</description><pubDate>Tue, 07 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;a-list-of-numbered-things&quot;&gt;&lt;a href=&quot;#a-list-of-numbered-things&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “A List of Numbered Things”&quot;&gt;A List of Numbered Things&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; numberedThings &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Godfather&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Godfather 3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Scream&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Scream 2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Scream 3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Scream 1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Windows 10&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Windows 7&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Windows 11&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rocky 5&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rocky 2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rocky 4&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rocky 3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rock&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rocky&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Windows XP&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Godfather 2&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.11&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.10&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;10.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; numericOrderer &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;NumericOrderer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; sorted &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; numberedThings&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OrderBy&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; x, numericOrderer)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToList&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; item &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; sorted)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(item);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var numberedThings = new List&lt;string&gt;{    &amp;quot;Godfather&amp;quot;, &amp;quot;Godfather 3&amp;quot;, &amp;quot;Scream&amp;quot;,    &amp;quot;Scream 2&amp;quot;, &amp;quot;Scream 3&amp;quot;, &amp;quot;Scream 1&amp;quot;,    &amp;quot;Windows 10&amp;quot;, &amp;quot;Windows 7&amp;quot;,    &amp;quot;Windows 11&amp;quot;, &amp;quot;Rocky 5&amp;quot;,    &amp;quot;Rocky 2&amp;quot;, &amp;quot;Rocky 4&amp;quot;, &amp;quot;Rocky 3&amp;quot;, &amp;quot;Rock&amp;quot;,    &amp;quot;1.2&amp;quot;, &amp;quot;1.3&amp;quot;, &amp;quot;1.1&amp;quot;, &amp;quot;Rocky&amp;quot;, &amp;quot;Windows XP&amp;quot;,    &amp;quot;Godfather 2&amp;quot;, &amp;quot;1.11&amp;quot;, &amp;quot;1.10&amp;quot;, &amp;quot;10.0&amp;quot;, &amp;quot;1.0&amp;quot;};var numericOrderer = new NumericOrderer();var sorted = numberedThings    .OrderBy(x =&gt; x, numericOrderer)    .ToList();foreach (var item in sorted){    Console.WriteLine(item);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1.11&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;10.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Godfather&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Godfather 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Godfather 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rocky&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rocky 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rocky 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rocky 4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Rocky 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Scream&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Scream 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Scream 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Scream 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Windows 7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Windows 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Windows 11&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;Windows XP&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s look at my implementation.&lt;/p&gt;
&lt;h2 id=&quot;writing-a-numericorderer-with-spans&quot;&gt;&lt;a href=&quot;#writing-a-numericorderer-with-spans&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Writing a NumericOrderer with Spans”&quot;&gt;Writing a NumericOrderer with Spans&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;NumericOrderer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IComparer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Compare&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (y &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xSpan &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; x.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AsSpan&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ySpan &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; y.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AsSpan&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; commonPrefixLength &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xSpan.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CommonPrefixLength&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ySpan);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (commonPrefixLength &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;xSpan &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xSpan[commonPrefixLength&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;ySpan &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ySpan[commonPrefixLength&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;commonPrefixLength &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xSpan.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CommonPrefixLength&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ySpan);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryParse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(xSpan, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xNumber) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TryParse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ySpan, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; yNumber))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xNumber.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CompareTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(yNumber);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; xSpan.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CompareTo&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ySpan, StringComparison.Ordinal);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public sealed class NumericOrderer : IComparer&lt;string&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 &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);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>dotnet</category></item><item><title>Great .NET Documentation with Astro, Starlight, and MarkdownSnippets</title><link>https://khalidabuhakmeh.com/posts/great-dotnet-documentation-with-astro-starlight-and-markdownsnippets/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/great-dotnet-documentation-with-astro-starlight-and-markdownsnippets/</guid><description>Combine Astro Starlight with MarkdownSnippets to keep .NET documentation code samples synced automatically with your real, compiling source code.</description><pubDate>Tue, 31 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;directory-structure-and-tools&quot;&gt;&lt;a href=&quot;#directory-structure-and-tools&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Directory Structure and Tools”&quot;&gt;Directory Structure and Tools&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- docs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- src&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;- docs- src&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;tool-manifest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet new tool-manifest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Next, let’s install the MarkdownSnippets tool.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;MarkdownSnippets.Tool&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet tool install MarkdownSnippets.Tool&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;$schema&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/refs/heads/main/schema.json&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Convention&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;InPlaceOverwrite&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;WriteHeader&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;ReadOnly&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;LinkFormat&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;OmitSnippetLinks&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;$schema&amp;quot;: &amp;quot;https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/refs/heads/main/schema.json&amp;quot;,  &amp;quot;Convention&amp;quot;: &amp;quot;InPlaceOverwrite&amp;quot;,  &amp;quot;WriteHeader&amp;quot;: false,  &amp;quot;ReadOnly&amp;quot;: false,  &amp;quot;LinkFormat&amp;quot;: &amp;quot;None&amp;quot;,  &amp;quot;OmitSnippetLinks&amp;quot;: true}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Following the steps correctly, you’ll have the following files and folders.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- docs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- src&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- .config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- mdsnippets.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;- docs- src- .config- mdsnippets.json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#our-net-code-samples&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Our .NET Code Samples”&quot;&gt;Our .NET Code Samples&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Program.cs&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// begin-snippet: App:HelloWorld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello, Again!&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// end-snippet&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// begin-snippet: App:HelloWorldConsole.WriteLine(&amp;quot;Hello, Again!&amp;quot;);// end-snippet&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#our-starlight-documentation&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Our Starlight Documentation”&quot;&gt;Our Starlight Documentation&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;yarn create astro --template starlight&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;yarn create astro --template starlight&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- docs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- .astro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- .vscode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- .yarn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- src&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- public&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- astro.config.mjs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- package.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- src&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- App&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- bin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- obj&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- App.csproj&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- Program.cs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;- mdsnippets.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;- docs  - .astro  - .vscode  - .yarn  - src  - public  - astro.config.mjs  - package.json  - ...- src  - App    - bin    - obj    - App.csproj    - Program.cs- mdsnippets.json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;0.0.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;scripts&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;mdsnippets&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;cd .. &amp;amp;&amp;amp; dotnet mdsnippets&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;npm run mdsnippets &amp;amp;&amp;amp; astro dev&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;npm run dev&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;npm run mdsnippets &amp;amp;&amp;amp; astro build&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;dependencies&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;@astrojs/starlight&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;^0.29.3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;astro&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;^4.16.10&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;sharp&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;^0.32.5&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;,  &amp;quot;version&amp;quot;: &amp;quot;0.0.1&amp;quot;,  &amp;quot;scripts&amp;quot;: {    &amp;quot;mdsnippets&amp;quot;: &amp;quot;cd .. &amp;amp;&amp;amp; dotnet mdsnippets&amp;quot;,    &amp;quot;dev&amp;quot;: &amp;quot;npm run mdsnippets &amp;amp;&amp;amp; astro dev&amp;quot;,    &amp;quot;start&amp;quot;: &amp;quot;npm run dev&amp;quot;,    &amp;quot;build&amp;quot;: &amp;quot;npm run mdsnippets &amp;amp;&amp;amp; astro build&amp;quot;  },  &amp;quot;dependencies&amp;quot;: {    &amp;quot;@astrojs/starlight&amp;quot;: &amp;quot;^0.29.3&amp;quot;,    &amp;quot;astro&amp;quot;: &amp;quot;^4.16.10&amp;quot;,    &amp;quot;sharp&amp;quot;: &amp;quot;^0.32.5&amp;quot;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello, World!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Creating your first .NET Console Application&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BD93F9;--0fw:bold&quot;&gt;## Getting Started&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;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&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`dotnet`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; CLI command &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`new`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```bash title=&quot;Terminal&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;-o&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;HelloWorld&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;./HelloWorld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Then, add the following code in the &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`Program.cs`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; file.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;snippet: App:HelloWorld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Then run the app by using the following command.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```bash title=&quot;Terminal&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;run&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Congratulations!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---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&amp;#x60;dotnet&amp;#x60; CLI command &amp;#x60;new&amp;#x60;.&amp;#x60;&amp;#x60;&amp;#x60;bash title=&amp;quot;Terminal&amp;quot;dotnet new console -o HelloWorld &amp;amp;&amp;amp; cd ./HelloWorld&amp;#x60;&amp;#x60;&amp;#x60;Then, add the following code in the &amp;#x60;Program.cs&amp;#x60; file.snippet: App:HelloWorldThen run the app by using the following command.&amp;#x60;&amp;#x60;&amp;#x60;bash title=&amp;quot;Terminal&amp;quot;dotnet run&amp;#x60;&amp;#x60;&amp;#x60;Congratulations!&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello, World!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Creating your first .NET Console Application&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BD93F9;--0fw:bold&quot;&gt;## Getting Started&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;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&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`dotnet`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; CLI command &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`new`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```bash title=&quot;Terminal&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;-o&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;HelloWorld&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;./HelloWorld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Then, add the following code in the &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;`Program.cs`&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; file.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- snippet: App:HelloWorld --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```cs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Program.cs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello, Again!&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- endSnippet --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Then run the app by using the following command.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```bash title=&quot;Terminal&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;run&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Congratulations!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---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&amp;#x60;dotnet&amp;#x60; CLI command &amp;#x60;new&amp;#x60;.&amp;#x60;&amp;#x60;&amp;#x60;bash title=&amp;quot;Terminal&amp;quot;dotnet new console -o HelloWorld &amp;amp;&amp;amp; cd ./HelloWorld&amp;#x60;&amp;#x60;&amp;#x60;Then, add the following code in the &amp;#x60;Program.cs&amp;#x60; file.&lt;!-- snippet: App:HelloWorld --&gt;&amp;#x60;&amp;#x60;&amp;#x60;cs// Program.csConsole.WriteLine(&amp;quot;Hello, Again!&amp;quot;);&amp;#x60;&amp;#x60;&amp;#x60;&lt;!-- endSnippet --&gt;Then run the app by using the following command.&amp;#x60;&amp;#x60;&amp;#x60;bash title=&amp;quot;Terminal&amp;quot;dotnet run&amp;#x60;&amp;#x60;&amp;#x60;Congratulations!&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>astro</category><category>javascript</category><category>dotnet</category></item><item><title>Alpine.Js Polling ASP.NET Core APIs For Updates</title><link>https://khalidabuhakmeh.com/posts/alpinejs-polling-aspnet-core-apis-for-updates/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/alpinejs-polling-aspnet-core-apis-for-updates/</guid><description>Discover how Alpine.js lets you poll an ASP.NET Core API and update the DOM reactively, building a real-time UI with minimal JavaScript code.</description><pubDate>Tue, 24 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;the-strength-of-alpinejs&quot;&gt;&lt;a href=&quot;#the-strength-of-alpinejs&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Strength of Alpine.js”&quot;&gt;The Strength of Alpine.js&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://alpinejs.dev/&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;{ count: 0 }&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count++&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Increment&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div x-data=&amp;quot;{ count: 0 }&amp;quot;&gt;    &lt;button x-on:click=&amp;quot;count++&amp;quot;&gt;Increment&lt;/button&gt;    &lt;span x-text=&amp;quot;count&amp;quot;&gt;&lt;/span&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;increment()&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Increment&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alpine:init&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div x-data=&amp;quot;count&amp;quot;&gt;    &lt;button x-on:click=&amp;quot;increment()&amp;quot;&gt;Increment&lt;/button&gt;    &lt;span x-text=&amp;quot;value&amp;quot;&gt;&lt;/span&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#aspnet-core-and-alpinejs&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “ASP.NET Core and Alpine.Js”&quot;&gt;ASP.NET Core and Alpine.Js&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Weather&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Location { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Description { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Temperature { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ReadOnlySpan&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; Descriptions &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Sunny&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Cloudy&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Rainy&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Snowy&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ReadOnlySpan&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; Locations &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Mountain&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Valley&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Desert&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Forest&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class Weather{    public string Location { get; set; } = &amp;quot;&amp;quot;;    public string Description { get; set; } = &amp;quot;&amp;quot;;    public string Temperature { get; set; } = &amp;quot;&amp;quot;;    public static ReadOnlySpan&lt;string&gt; Descriptions =&gt;        new([&amp;quot;Sunny&amp;quot;, &amp;quot;Cloudy&amp;quot;, &amp;quot;Rainy&amp;quot;, &amp;quot;Snowy&amp;quot;]);    public static ReadOnlySpan&lt;string&gt; Locations =&gt;        new([&amp;quot;Mountain&amp;quot;, &amp;quot;Valley&amp;quot;, &amp;quot;Desert&amp;quot;, &amp;quot;Forest&amp;quot;]);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MountainWeather&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; WebApplication.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; app &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/weather&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Results.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Json&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Enumerable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Range&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Select&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Weather&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Location &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Random&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Shared&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetItems&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Weather&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Locations&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)[&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; #&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Description &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Random&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Shared&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetItems&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Weather&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Descriptions&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)[&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Temperature &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Random&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Shared&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;℉&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToList&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseDefaultFiles&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseStaticFiles&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using MountainWeather.Models;var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.MapGet(&amp;quot;/weather&amp;quot;, () =&gt;{    return Results.Json(        Enumerable            .Range(1, 10)            .Select(i =&gt; new Weather            {                Location = $&amp;quot;{Random.Shared.GetItems(Weather.Locations, 1)[0]} #{i}&amp;quot;,                Description = $&amp;quot;{Random.Shared.GetItems(Weather.Descriptions, 1)[0]}&amp;quot;,                Temperature = $&amp;quot;{Random.Shared.Next(32, 100)}℉&amp;quot;            })            .ToList()    );});app.UseDefaultFiles();app.UseStaticFiles();app.Run();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;en&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;UTF-8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Weather&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;stylesheet&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://unpkg.com/@picocss/pico@latest/css/pico.min.css&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;container-fluid&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;table table-striped&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;thead&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Location&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Description&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Temperature&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;thead&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tbody&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-show&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;locations.length === 0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;colspan&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;0 Locations Found.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-for&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;l in locations&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;l.location&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;l.description&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;l.temperature&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tbody&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tfoot&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;colspan&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;updated&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;tfoot&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;getWeather&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/weather&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;result.locations &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; response.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;result.updated &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6;--0fw:bold&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alpine:init&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.timer &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;setInterval&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;getWeather&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.locations &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result.locations;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.updated &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result.updated;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;3000&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;getWeather&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.locations &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result.locations;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.updated &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; result.updated;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;clearInterval&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.timer);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;locations&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;updated&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;n/a&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;timer&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!DOCTYPE html&gt;&lt;html lang=&amp;quot;en&amp;quot;&gt;&lt;head&gt;    &lt;meta charset=&amp;quot;UTF-8&amp;quot;&gt;    &lt;title&gt;Weather&lt;/title&gt;    &lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://unpkg.com/@picocss/pico@latest/css/pico.min.css&amp;quot;&gt;    &lt;/head&gt;&lt;body&gt;&lt;main class=&amp;quot;container-fluid&amp;quot;&gt;    &lt;table class=&amp;quot;table table-striped&amp;quot; x-data=&amp;quot;weather&amp;quot;&gt;        &lt;thead&gt;        &lt;tr&gt;            &lt;th&gt;Location&lt;/th&gt;            &lt;th&gt;Description&lt;/th&gt;            &lt;th&gt;Temperature&lt;/th&gt;        &lt;/tr&gt;        &lt;/thead&gt;        &lt;tbody&gt;        &lt;tr x-show=&amp;quot;locations.length === 0&amp;quot;&gt;            &lt;td colspan=&amp;quot;3&amp;quot;&gt;                0 Locations Found.            &lt;/td&gt;        &lt;/tr&gt;        &lt;template x-for=&amp;quot;l in locations&amp;quot;&gt;            &lt;tr&gt;                &lt;td x-text=&amp;quot;l.location&amp;quot;&gt;&lt;/td&gt;                &lt;td x-text=&amp;quot;l.description&amp;quot;&gt;&lt;/td&gt;                &lt;td x-text=&amp;quot;l.temperature&amp;quot;&gt;&lt;/td&gt;            &lt;/tr&gt;        &lt;/template&gt;        &lt;/tbody&gt;        &lt;tfoot&gt;        &lt;tr&gt;            &lt;td colspan=&amp;quot;3&amp;quot; x-text=&amp;quot;updated&amp;quot;&gt;&lt;/td&gt;        &lt;/tr&gt;        &lt;/tfoot&gt;    &lt;/table&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>aspnetcore</category><category>javascript</category><category>csharp</category></item><item><title>Building a Persistent Counter with Alpine.Js</title><link>https://khalidabuhakmeh.com/posts/building-a-persistent-counter-with-alpinejs/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/building-a-persistent-counter-with-alpinejs/</guid><description>Using the JavaScript library Alpine.Js to recreate the Blazor Counter example</description><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;installing-alpinejs&quot;&gt;&lt;a href=&quot;#installing-alpinejs&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Installing Alpine.js”&quot;&gt;Installing Alpine.js&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- Alpine Core --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!-- Alpine Core --&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#building-an-inline-counter-with-alpine&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Building an inline Counter with Alpine”&quot;&gt;Building an inline Counter with Alpine&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;{ count : 0 }&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Counter Value&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count++&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Increment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count = 0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Reset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;main class=&amp;quot;container&amp;quot; x-data=&amp;quot;{ count : 0 }&amp;quot;&gt;    &lt;article class=&amp;quot;card&amp;quot;&gt;        &lt;header&gt;            &lt;h3&gt;Counter Value&lt;/h3&gt;        &lt;/header&gt;        &lt;section&gt;            &lt;p x-text=&amp;quot;count&amp;quot;&gt;&lt;/p&gt;        &lt;/section&gt;    &lt;/article&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;count++&amp;quot;&gt;        Increment    &lt;/button&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;count = 0&amp;quot;&gt;        Reset    &lt;/button&gt;&lt;/main&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#making-the-inline-counter-persistent&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Making the inline counter persistent”&quot;&gt;Making the inline counter persistent&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- Alpine Plugins --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- Alpine Core --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!-- Alpine Plugins --&gt;&lt;!-- Alpine Core --&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Cool, we’re ready to update the HTML to persist the value across page refreshes.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;{ count : $persist(0) }&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Counter Value&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count++&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Increment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;count = 0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Reset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;main class=&amp;quot;container&amp;quot; x-data=&amp;quot;{ count : $persist(0) }&amp;quot;&gt;    &lt;article class=&amp;quot;card&amp;quot;&gt;        &lt;header&gt;            &lt;h3&gt;Counter Value&lt;/h3&gt;        &lt;/header&gt;        &lt;section&gt;            &lt;p x-text=&amp;quot;count&amp;quot;&gt;&lt;/p&gt;        &lt;/section&gt;    &lt;/article&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;count++&amp;quot;&gt;        Increment    &lt;/button&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;count = 0&amp;quot;&gt;        Reset    &lt;/button&gt;&lt;/main&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#persisting-state-in-an-alpine-store&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Persisting state in an Alpine Store”&quot;&gt;Persisting state in an Alpine Store&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Counter Value&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.increment()&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Increment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.reset()&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Reset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alpine:initializing&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;counter&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;$persist&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;++&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;reset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;body&gt;    &lt;main class=&amp;quot;container&amp;quot; x-data&gt;        &lt;article class=&amp;quot;card&amp;quot;&gt;            &lt;header&gt;                &lt;h3&gt;Counter Value&lt;/h3&gt;            &lt;/header&gt;            &lt;section&gt;                &lt;p x-text=&amp;quot;$store.counter.value&amp;quot;&gt;&lt;/p&gt;            &lt;/section&gt;        &lt;/article&gt;        &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;$store.counter.increment()&amp;quot;&gt;            Increment        &lt;/button&gt;        &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;$store.counter.reset()&amp;quot;&gt;            Reset        &lt;/button&gt;    &lt;/main&gt;    &lt;/body&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;en&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;xmlns:x-on&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;http://www.w3.org/1999/xhtml&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;UTF-8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;PicoCSS Boilerplate&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;link&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;stylesheet&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;stylesheet&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/css/site.css&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;viewport&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;width=device-width, initial-scale=1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;color-scheme&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;light dark&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Hello World!&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- Alpine Plugins --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- Alpine Core --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Counter Value&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-text&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.increment()&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Increment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;x-on:click&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;$store.counter.reset()&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Reset&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alpine:initializing&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;counter&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Alpine.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;$persist&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;++&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;reset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.value &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!DOCTYPE html&gt;&lt;html lang=&amp;quot;en&amp;quot; xmlns:x-on=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&gt;&lt;head&gt;    &lt;meta charset=&amp;quot;UTF-8&amp;quot;&gt;    &lt;title&gt;PicoCSS Boilerplate&lt;/title&gt;    &lt;link            rel=&amp;quot;stylesheet&amp;quot;            href=&amp;quot;https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css&amp;quot;    /&gt;    &lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;/css/site.css&amp;quot;/&gt;    &lt;meta charset=&amp;quot;utf-8&amp;quot;&gt;    &lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot;&gt;    &lt;meta name=&amp;quot;color-scheme&amp;quot; content=&amp;quot;light dark&amp;quot;/&gt;    &lt;title&gt;Hello World!&lt;/title&gt;    &lt;!-- Alpine Plugins --&gt;        &lt;!-- Alpine Core --&gt;    &lt;/head&gt;&lt;body&gt;&lt;main class=&amp;quot;container&amp;quot; x-data&gt;    &lt;article class=&amp;quot;card&amp;quot;&gt;        &lt;header&gt;            &lt;h3&gt;Counter Value&lt;/h3&gt;        &lt;/header&gt;        &lt;section&gt;            &lt;p x-text=&amp;quot;$store.counter.value&amp;quot;&gt;&lt;/p&gt;        &lt;/section&gt;    &lt;/article&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;$store.counter.increment()&amp;quot;&gt;        Increment    &lt;/button&gt;    &lt;button type=&amp;quot;button&amp;quot; x-on:click=&amp;quot;$store.counter.reset()&amp;quot;&gt;        Reset    &lt;/button&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>javascript</category><category>html</category></item><item><title>Dynamic Htmx Islands with ASP.NET Core</title><link>https://khalidabuhakmeh.com/posts/dynamic-htmx-islands-with-aspnet-core/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/dynamic-htmx-islands-with-aspnet-core/</guid><description>Using TagHelpers to create an Htmx-powered Islands implementation for ASP.NET Core</description><pubDate>Tue, 19 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;what-is-an-island&quot;&gt;&lt;a href=&quot;#what-is-an-island&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “What is an Island?”&quot;&gt;What is an Island?&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;&lt;a href=&quot;#the-island-plan&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Island Plan”&quot;&gt;The Island Plan&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7777;--0fs:italic;--0td:underline&quot;&gt;island&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/profile/avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert alert-info d-flex justify-content-center vertical-align-center&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;spinner-border&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;visually-hidden&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Loading...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF7777;--0fs:italic;--0td:underline&quot;&gt;island&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;island url=&amp;quot;/profile/avatar&amp;quot;&gt;    &lt;div class=&amp;quot;alert alert-info d-flex justify-content-center vertical-align-center&amp;quot;&gt;        &lt;div class=&amp;quot;spinner-border&amp;quot; role=&amp;quot;status&amp;quot;&gt;            &lt;span class=&amp;quot;visually-hidden&amp;quot;&gt;Loading...&lt;/span&gt;        &lt;/div&gt;    &lt;/div&gt;&lt;/island&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/profile/avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Results.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//lang=html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;p class=&quot;fs-1 fw-bold&quot;&amp;gt;🌴 Welcome to the island Khalid!&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;p class=&quot;fs-3&quot;&amp;gt;You arrived on (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Now&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToLongTimeString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;app.MapGet(&amp;quot;/profile/avatar&amp;quot;, () =&gt; Results.Content(    //lang=html    $&amp;quot;&amp;quot;&amp;quot;     &lt;div class=&amp;quot;alert alert-info&amp;quot;&gt;        &lt;p class=&amp;quot;fs-1 fw-bold&amp;quot;&gt;🌴 Welcome to the island Khalid!&lt;/p&gt;        &lt;p class=&amp;quot;fs-3&amp;quot;&gt;You arrived on ({DateTime.Now.ToLongTimeString()})&lt;/p&gt;     &lt;/div&gt;     &amp;quot;&amp;quot;&amp;quot;));&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;OK, let’s build it!&lt;/p&gt;
&lt;h2 id=&quot;creating-an-island-taghelper&quot;&gt;&lt;a href=&quot;#creating-an-island-taghelper&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Creating an Island TagHelper”&quot;&gt;Creating an Island TagHelper&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ComponentModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DataAnnotations&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Razor&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelpers&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IslandEvents&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Load,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Revealed,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Intersect&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlTargetElement&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;island&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;IslandTagHelper&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelper&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlAttributeName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Required&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? Url { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmlAttributeName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IslandEvents&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Event { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; IslandEvents.Load;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ProcessAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelperContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TagHelperOutput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Changing the tag name to &quot;div&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.TagName &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; @event &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Event &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IslandEvents&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IslandEvents&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Revealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;revealed&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IslandEvents&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Intersect&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;intersect once&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Attributes.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;hx-get&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, Url);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Attributes.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;hx-trigger&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, @event);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Attributes.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetAttribute&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;hx-swap&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;outerHTML&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Retrieve the inner content&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; childContent &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; output.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetChildContentAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.Content.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;SetHtmlContent&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(childContent);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Ensuring the tag is not self-closing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;output.TagMode &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; TagMode.StartTagAndEndTag;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using System.ComponentModel.DataAnnotations;using Microsoft.AspNetCore.Razor.TagHelpers;public enum IslandEvents{    Load,    Revealed,    Intersect}[HtmlTargetElement(&amp;quot;island&amp;quot;)]public class IslandTagHelper : TagHelper{    [HtmlAttributeName(&amp;quot;url&amp;quot;), Required]    public string? Url { get; set; }    [HtmlAttributeName(&amp;quot;event&amp;quot;)]    public IslandEvents Event { get; set; } = IslandEvents.Load;    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)    {        // Changing the tag name to &amp;quot;div&amp;quot;        output.TagName = &amp;quot;div&amp;quot;;        var @event = Event switch        {            IslandEvents.Load =&gt; &amp;quot;load&amp;quot;,            IslandEvents.Revealed =&gt; &amp;quot;revealed&amp;quot;,            IslandEvents.Intersect =&gt; &amp;quot;intersect once&amp;quot;,            _ =&gt; &amp;quot;load&amp;quot;        };        output.Attributes.SetAttribute(&amp;quot;hx-get&amp;quot;, Url);        output.Attributes.SetAttribute(&amp;quot;hx-trigger&amp;quot;, @event);        output.Attributes.SetAttribute(&amp;quot;hx-swap&amp;quot;, &amp;quot;outerHTML&amp;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;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;https://unpkg.com/htmx.org@2.0.3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;margin-top: 2000px&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7777;--0fs:italic;--0td:underline&quot;&gt;island&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/profile/avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Revealed&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert alert-info d-flex justify-content-center vertical-align-center&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;spinner-border&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;visually-hidden&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Loading...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF7777;--0fs:italic;--0td:underline&quot;&gt;island&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div style=&amp;quot;margin-top: 2000px&amp;quot;&gt;    &lt;island url=&amp;quot;/profile/avatar&amp;quot; event=&amp;quot;Revealed&amp;quot;&gt;        &lt;div class=&amp;quot;alert alert-info d-flex justify-content-center vertical-align-center&amp;quot;&gt;            &lt;div class=&amp;quot;spinner-border&amp;quot; role=&amp;quot;status&amp;quot;&gt;                &lt;span class=&amp;quot;visually-hidden&amp;quot;&gt;Loading...&lt;/span&gt;            &lt;/div&gt;        &lt;/div&gt;    &lt;/island&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#response-and-output-caching&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Response and Output Caching”&quot;&gt;Response and Output Caching&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddOutputCache&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddResponseCaching&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;builder.Services.AddOutputCache();builder.Services.AddResponseCaching();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseResponseCaching&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseOutputCache&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;app.UseResponseCaching();app.UseOutputCache();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;RazorPages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OutputCaching&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;OutputCache&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Duration &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ResponseCache&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Duration &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Location &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ResponseCacheLocation.Any,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;NoStore &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ILogger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PageModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ILogger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; logger &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; logger;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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&lt;IndexModel&gt; logger) : PageModel{    private readonly ILogger&lt;IndexModel&gt; logger = logger;    public void OnGet()    {    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;app.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MapGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;/profile/avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Results.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;//lang=html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;div class=&quot;alert alert-info&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;p class=&quot;fs-1 fw-bold&quot;&amp;gt;🌴 Welcome to the island Khalid!&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;p class=&quot;fs-3&quot;&amp;gt;You arrived on (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;DateTime&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Now&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToLongTimeString&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CacheOutput&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;policy&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;/* apply caching policy here */&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;app.MapGet(&amp;quot;/profile/avatar&amp;quot;, () =&gt; Results.Content(    //lang=html    $&amp;quot;&amp;quot;&amp;quot;     &lt;div class=&amp;quot;alert alert-info&amp;quot;&gt;        &lt;p class=&amp;quot;fs-1 fw-bold&amp;quot;&gt;🌴 Welcome to the island Khalid!&lt;/p&gt;        &lt;p class=&amp;quot;fs-3&amp;quot;&gt;You arrived on ({DateTime.Now.ToLongTimeString()})&lt;/p&gt;     &lt;/div&gt;     &amp;quot;&amp;quot;&amp;quot;))    .CacheOutput(policy =&gt; { /* apply caching policy here */ });&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;a href=&quot;https://www.computerworld.com/article/1604649/what-exactly-is-donut-caching.html&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;donut caching&lt;/em&gt; and _donut hole caching&lt;/a&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&quot;&gt;GitHub repository and try it out for yourself&lt;/a&gt;&lt;/strong&gt;. Cheers.&lt;/p&gt;
</content:encoded><category>aspnet</category><category>htmx</category></item><item><title>Update HTML Elements with Htmx Triggers and ASP.NET Core</title><link>https://khalidabuhakmeh.com/posts/update-html-elements-with-htmx-triggers-and-aspnet-core/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/update-html-elements-with-htmx-triggers-and-aspnet-core/</guid><description>Using HX-Trigger response headers you can force UI elements to update when server changes occur</description><pubDate>Tue, 22 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let me start by saying that I love the combination of &lt;a href=&quot;https://htmx.org&quot; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;the-moving-parts&quot;&gt;&lt;a href=&quot;#the-moving-parts&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Moving Parts”&quot;&gt;The Moving Parts&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;&lt;a href=&quot;#the-user-service&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The User Service”&quot;&gt;The User Service&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;UserService&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;readonly&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] AvatarUrls &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;~/img/avatar_one.png&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;~/img/avatar_two.png&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;~/img/avatar_three.png&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Name { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Khalid Abuhakmeh&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; AvatarUrl { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; AvatarUrls[&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public class UserService{    public static readonly string[] AvatarUrls =    [        &amp;quot;~/img/avatar_one.png&amp;quot;,        &amp;quot;~/img/avatar_two.png&amp;quot;,        &amp;quot;~/img/avatar_three.png&amp;quot;,    ];    public string Name { get; set; } = &amp;quot;Khalid Abuhakmeh&amp;quot;;    public string AvatarUrl { get; set; } = AvatarUrls[0];}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; WebApplication.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// Add services to the container.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddRazorPages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;builder.Services.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddSingleton&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; app &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Build&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddRazorPages();builder.Services.AddSingleton&lt;UserService&gt;();var app = builder.Build();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@inject&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; UserService&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;&amp;lt;!-- some HTML --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@await &lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Html.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;PartialAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, UserService)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@inject UserService UserService&lt;!-- some HTML --&gt;@await Html.PartialAsync(&amp;quot;_Avatar&amp;quot;, UserService)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#profile-endpoints&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Profile Endpoints”&quot;&gt;Profile Endpoints&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;System&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Diagnostics&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CodeAnalysis&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Htmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxAvatarChange&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;RazorPages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Rendering&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxAvatarChange&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Pages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ILogger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PageModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;BindProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? Name { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;BindProperty&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? AvatarUrl { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TempData&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? Message { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TempData&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? MessageCssClass { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;MemberNotNullWhen&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(Message))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; HasMessage &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Message &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SelectListItem&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; Avatars &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; UserService&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.AvatarUrls&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Select&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;SelectListItem&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;avatar-&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;00&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, x))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToList&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; userService.Name;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;AvatarUrl &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; userService.AvatarUrl;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnPost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (ModelState.IsValid)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Message &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Successfully saved account settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MessageCssClass &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert-success&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// change values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;userService.Name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;userService.AvatarUrl &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; AvatarUrl&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Response.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Htmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;h.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WithTrigger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Message &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Failed to save account settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MessageCssClass &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert-danger&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (Request.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;IsHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Form&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RedirectToPage&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGetAvatar&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, userService);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;IsCurrentAvatar&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;avatarValue&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; avatarValue &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; AvatarUrl &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;checked&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;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&lt;IndexModel&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 =&gt; Message != null;    public List&lt;SelectListItem&gt; Avatars =&gt; UserService        .AvatarUrls        .Select((x, i) =&gt; new SelectListItem($&amp;quot;avatar-{i:00}&amp;quot;, x))        .ToList();    public void OnGet()    {        Name = userService.Name;        AvatarUrl = userService.AvatarUrl;    }    public IActionResult OnPost()    {        if (ModelState.IsValid)        {            Message = &amp;quot;Successfully saved account settings&amp;quot;;            MessageCssClass = &amp;quot;alert-success&amp;quot;;            // change values            userService.Name = Name!;            userService.AvatarUrl = AvatarUrl!;            Response.Htmx(h =&gt;                h.WithTrigger(&amp;quot;avatar&amp;quot;));        }        else        {            Message = &amp;quot;Failed to save account settings&amp;quot;;            MessageCssClass = &amp;quot;alert-danger&amp;quot;;        }        if (Request.IsHtmx())        {            return Partial(&amp;quot;_Form&amp;quot;, this);        }        return RedirectToPage(&amp;quot;Index&amp;quot;);    }    public IActionResult OnGetAvatar()    {        return Partial(&amp;quot;_Avatar&amp;quot;, userService);    }    public string? IsCurrentAvatar(string avatarValue)    {        return avatarValue == AvatarUrl ? &amp;quot;checked&amp;quot; : null;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; userService.Name;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;AvatarUrl &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; userService.AvatarUrl;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public void OnGet(){  Name = userService.Name;  AvatarUrl = userService.AvatarUrl;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGetAvatar&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, userService);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public IActionResult OnGetAvatar(){  return Partial(&amp;quot;_Avatar&amp;quot;, userService);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnPost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (ModelState.IsValid)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Message &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Successfully saved account settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MessageCssClass &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert-success&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// change values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;userService.Name &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Name&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;userService.AvatarUrl &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; AvatarUrl&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Response.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Htmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;h.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WithTrigger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Message &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Failed to save account settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MessageCssClass &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert-danger&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (Request.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;IsHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Form&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RedirectToPage&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public IActionResult OnPost(){  if (ModelState.IsValid)  {    Message = &amp;quot;Successfully saved account settings&amp;quot;;    MessageCssClass = &amp;quot;alert-success&amp;quot;;    // change values    userService.Name = Name!;    userService.AvatarUrl = AvatarUrl!;    Response.Htmx(h =&gt;      h.WithTrigger(&amp;quot;avatar&amp;quot;));  }  else  {    Message = &amp;quot;Failed to save account settings&amp;quot;;    MessageCssClass = &amp;quot;alert-danger&amp;quot;;  }  if (Request.IsHtmx())  {    return Partial(&amp;quot;_Form&amp;quot;, this);  }  return RedirectToPage(&amp;quot;Index&amp;quot;);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Response.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Htmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;h.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WithTrigger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Response.Htmx(h =&gt;  h.WithTrigger(&amp;quot;avatar&amp;quot;));&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (Request.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;IsHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Form&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9;--0fs:italic&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if (Request.IsHtmx()){  return Partial(&amp;quot;_Form&amp;quot;, this);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#htmx-and-partial-views&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Htmx and Partial Views”&quot;&gt;Htmx and Partial Views&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@model&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IndexModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;account-settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Account Settings&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (Model.HasMessage)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;MessageCssClass&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert-info&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;alert&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Message&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-post&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-target&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;#account-settings&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-swap&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;outerHTML&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-group row&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;asp-for&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-sm-2 col-form-label&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Name&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-sm-10&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-control&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;asp-for&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-group mt-3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;row&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-form-label col-sm-2 pt-0&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Avatar&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;col-sm-10&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@foreach&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; avatar &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Model.Avatars)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-check&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;asp-for&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;AvatarUrl&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-check-inline&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;radio&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                                &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;checked&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;IsCurrentAvatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-check-label&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Url&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;profile-pic&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;alt&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;avatar&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;form-group row mt-3&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;btn btn-primary&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Save Profile&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@model IndexModel&lt;fieldset id=&amp;quot;account-settings&amp;quot;&gt;    &lt;legend&gt;Account Settings&lt;/legend&gt;    @if (Model.HasMessage)    {        &lt;div class=&amp;quot;alert @(Model.MessageCssClass ?? &amp;quot;alert-info&amp;quot;)&amp;quot; role=&amp;quot;alert&amp;quot;&gt;            @Model.Message        &lt;/div&gt;    }    &lt;form method=&amp;quot;post&amp;quot; hx-post hx-target=&amp;quot;#account-settings&amp;quot; hx-swap=&amp;quot;outerHTML&amp;quot;&gt;        &lt;div class=&amp;quot;form-group row&amp;quot;&gt;            &lt;label asp-for=&amp;quot;Name&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&gt;Name&lt;/label&gt;            &lt;div class=&amp;quot;col-sm-10&amp;quot;&gt;                &lt;input class=&amp;quot;form-control&amp;quot; asp-for=&amp;quot;Name&amp;quot;&gt;            &lt;/div&gt;        &lt;/div&gt;        &lt;fieldset class=&amp;quot;form-group mt-3&amp;quot;&gt;            &lt;div class=&amp;quot;row&amp;quot;&gt;                &lt;legend class=&amp;quot;col-form-label col-sm-2 pt-0&amp;quot;&gt;Avatar&lt;/legend&gt;                &lt;div class=&amp;quot;col-sm-10&amp;quot;&gt;                    @foreach (var avatar in Model.Avatars)                    {                        &lt;div class=&amp;quot;form-check&amp;quot;&gt;                            &lt;input                                id=&amp;quot;@avatar.Text&amp;quot;                                asp-for=&amp;quot;AvatarUrl&amp;quot;                                class=&amp;quot;form-check-inline&amp;quot; type=&amp;quot;radio&amp;quot;                                value=&amp;quot;@avatar.Value&amp;quot;                                checked=&amp;quot;@Model.IsCurrentAvatar(avatar.Value)&amp;quot;&gt;                            &lt;label class=&amp;quot;form-check-label&amp;quot; for=&amp;quot;@avatar.Text&amp;quot;&gt;                                &lt;img src=&amp;quot;@Url.Content(avatar.Value)&amp;quot; class=&amp;quot;profile-pic&amp;quot; alt=&amp;quot;@avatar.Text&amp;quot;/&gt;                            &lt;/label&gt;                        &lt;/div&gt;                    }                &lt;/div&gt;            &lt;/div&gt;        &lt;/fieldset&gt;        &lt;div class=&amp;quot;form-group row mt-3&amp;quot;&gt;            &lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary&amp;quot;&gt;Save Profile&lt;/button&gt;        &lt;/div&gt;    &lt;/form&gt;&lt;/fieldset&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@model&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxAvatarChange&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Models&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;UserService&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;profile-avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;mx-2 smooth&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-get&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Url&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Page&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Avatar&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-trigger&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;avatar from:body&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;profile-pic&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Url&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;AvatarUrl&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;alt&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Profile Picture&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;navbar-text&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Name&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@model HtmxAvatarChange.Models.UserService&lt;div id=&amp;quot;profile-avatar&amp;quot;     class=&amp;quot;mx-2 smooth&amp;quot;     hx-get=&amp;quot;@Url.Page(&amp;quot;Index&amp;quot;, &amp;quot;Avatar&amp;quot;)&amp;quot;     hx-trigger=&amp;quot;avatar from:body&amp;quot;&gt;    &lt;div class=&amp;quot;profile-pic&amp;quot;&gt;        &lt;img src=&amp;quot;@Url.Content(Model.AvatarUrl)&amp;quot; alt=&amp;quot;Profile Picture&amp;quot;&gt;    &lt;/div&gt;    &lt;span class=&amp;quot;navbar-text&amp;quot;&gt; @Model.Name&lt;/span&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;hx-trigger=&quot;avatar from:body&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;hx-trigger=&amp;quot;avatar from:body&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;img src=&quot;https://github.com/khalidabuhakmeh/HtmxAvatarChange/raw/main/misc/htmx-hx-trigger-sample.gif&quot; alt=&quot;Sample Running&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
&lt;p&gt;Wow! That’s cool!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;
</content:encoded><category>htmx</category><category>aspnet</category><category>dotnet</category></item><item><title>Add EF Core Migrations to .NET Aspire Solutions</title><link>https://khalidabuhakmeh.com/posts/add-ef-core-migrations-to-dotnet-aspire-solutions/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/add-ef-core-migrations-to-dotnet-aspire-solutions/</guid><description>See how to add and manage Entity Framework Core migrations in a .NET Aspire distributed solution, bridging development-time tasks and runtime execution.</description><pubDate>Tue, 08 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;the-solution-structure&quot;&gt;&lt;a href=&quot;#the-solution-structure&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Solution Structure”&quot;&gt;The Solution Structure&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;AspireSandbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;|- AspireSandbox.AppHost&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;|- AspireSandbox.Data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;|- AspireSandbox.ServiceDefaults&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;|- AspireSandbox.Web&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;AspireSandbox|- AspireSandbox.AppHost|- AspireSandbox.Data|- AspireSandbox.ServiceDefaults|- AspireSandbox.Web&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;EntityFrameworkCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspireSandbox&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DbContextOptions&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DbContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(options)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DbSet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Count&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; Counts &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Count&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Count&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Id { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DateTimeOffset&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; CountedAt { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; DateTimeOffset.UtcNow;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using Microsoft.EntityFrameworkCore;namespace AspireSandbox.Data;public class Database(DbContextOptions&lt;Database&gt; options)    : DbContext(options){    public DbSet&lt;Count&gt; Counts =&gt; Set&lt;Count&gt;();}public class Count{    public int Id { get; set; }    public DateTimeOffset CountedAt { get; set; } = DateTimeOffset.UtcNow;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The dependencies for this project include the following Entity Framework Core packages.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.NET.Sdk&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;net8.0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.0.8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.EntityFrameworkCore.Design&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.0.8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;all&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Npgsql.EntityFrameworkCore.PostgreSQL&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.0.8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project Sdk=&amp;quot;Microsoft.NET.Sdk&amp;quot;&gt;    &lt;PropertyGroup&gt;        &lt;TargetFramework&gt;net8.0&lt;/TargetFramework&gt;        &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt;        &lt;Nullable&gt;enable&lt;/Nullable&gt;    &lt;/PropertyGroup&gt;    &lt;ItemGroup&gt;      &lt;PackageReference Include=&amp;quot;Microsoft.EntityFrameworkCore&amp;quot; Version=&amp;quot;8.0.8&amp;quot; /&gt;      &lt;PackageReference Include=&amp;quot;Microsoft.EntityFrameworkCore.Design&amp;quot; Version=&amp;quot;8.0.8&amp;quot;&gt;        &lt;PrivateAssets&gt;all&lt;/PrivateAssets&gt;        &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/IncludeAssets&gt;      &lt;/PackageReference&gt;      &lt;PackageReference Include=&amp;quot;Npgsql.EntityFrameworkCore.PostgreSQL&amp;quot; Version=&amp;quot;8.0.8&amp;quot; /&gt;    &lt;/ItemGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.NET.Sdk&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;OutputType&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Exe&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;OutputType&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;net8.0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;TargetFramework&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ImplicitUsings&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;enable&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Nullable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IsAspireHost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;true&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IsAspireHost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;UserSecretsId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;ba2648f9-6953-4e8b-9918-c241b1d99b09&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;UserSecretsId&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Aspire.Hosting.AppHost&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.2.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Aspire.Hosting.PostgreSQL&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.2.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Aspire.Hosting.Redis&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.2.1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.0.8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Microsoft.EntityFrameworkCore.Design&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;8.0.8&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;all&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;runtime; build; native; contentfiles; analyzers; buildtransitive&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;PackageReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ProjectReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;..\AspireSandbox.Data\AspireSandbox.Data.csproj&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;IsAspireProjectResource&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ProjectReference&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;..\AspireSandbox.Web\AspireSandbox.Web.csproj&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;ItemGroup&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;Project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;Project Sdk=&amp;quot;Microsoft.NET.Sdk&amp;quot;&gt;    &lt;PropertyGroup&gt;        &lt;OutputType&gt;Exe&lt;/OutputType&gt;        &lt;TargetFramework&gt;net8.0&lt;/TargetFramework&gt;        &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt;        &lt;Nullable&gt;enable&lt;/Nullable&gt;        &lt;IsAspireHost&gt;true&lt;/IsAspireHost&gt;        &lt;UserSecretsId&gt;ba2648f9-6953-4e8b-9918-c241b1d99b09&lt;/UserSecretsId&gt;    &lt;/PropertyGroup&gt;    &lt;ItemGroup&gt;        &lt;PackageReference Include=&amp;quot;Aspire.Hosting.AppHost&amp;quot; Version=&amp;quot;8.2.1&amp;quot;/&gt;        &lt;PackageReference Include=&amp;quot;Aspire.Hosting.PostgreSQL&amp;quot; Version=&amp;quot;8.2.1&amp;quot; /&gt;        &lt;PackageReference Include=&amp;quot;Aspire.Hosting.Redis&amp;quot; Version=&amp;quot;8.2.1&amp;quot; /&gt;        &lt;PackageReference Include=&amp;quot;Microsoft.EntityFrameworkCore&amp;quot; Version=&amp;quot;8.0.8&amp;quot; /&gt;        &lt;PackageReference Include=&amp;quot;Microsoft.EntityFrameworkCore.Design&amp;quot; Version=&amp;quot;8.0.8&amp;quot;&gt;          &lt;PrivateAssets&gt;all&lt;/PrivateAssets&gt;          &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/IncludeAssets&gt;        &lt;/PackageReference&gt;    &lt;/ItemGroup&gt;    &lt;ItemGroup&gt;      &lt;ProjectReference Include=&amp;quot;..\AspireSandbox.Data\AspireSandbox.Data.csproj&amp;quot;                        IsAspireProjectResource=&amp;quot;false&amp;quot; /&gt;      &lt;ProjectReference Include=&amp;quot;..\AspireSandbox.Web\AspireSandbox.Web.csproj&amp;quot; /&gt;    &lt;/ItemGroup&gt;&lt;/Project&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#entity-framework-core-design-time-factory&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Entity Framework Core Design Time Factory”&quot;&gt;Entity Framework Core Design Time Factory&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;EntityFrameworkCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;EntityFrameworkCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Design&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspireSandbox&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AppHost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;sealed&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;DataContextDesignTimeFactory&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; :&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IDesignTimeDbContextFactory&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CreateDbContext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; DistributedApplication.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; postgres &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddPostgres&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;postgres&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddDatabase&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;migrations&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;databaseName&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;migrations&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; optionsBuilder &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;DbContextOptionsBuilder&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;optionsBuilder.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;UseNpgsql&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;migrations&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(optionsBuilder.Options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using Microsoft.EntityFrameworkCore;using Microsoft.EntityFrameworkCore.Design;namespace AspireSandbox.AppHost;public sealed class DataContextDesignTimeFactory :  IDesignTimeDbContextFactory&lt;Data.Database&gt;{    public Data.Database CreateDbContext(string[] args)    {        var builder = DistributedApplication.CreateBuilder(args);        var postgres = builder            .AddPostgres(&amp;quot;postgres&amp;quot;)            .AddDatabase(&amp;quot;migrations&amp;quot;, databaseName: &amp;quot;migrations&amp;quot;);        var optionsBuilder = new DbContextOptionsBuilder&lt;Data.Database&gt;();        optionsBuilder.UseNpgsql(&amp;quot;migrations&amp;quot;);        return new Data.Database(optionsBuilder.Options);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#ef-core-cli-command&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “EF Core CLI Command”&quot;&gt;EF Core CLI Command&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;dotnet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;ef&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;migrations&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;--project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;./AspireSandbox.Data&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;--startup-project&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;./AspireSandbox.AppHost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Initial&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;dotnet ef migrations --project ./AspireSandbox.Data --startup-project ./AspireSandbox.AppHost add Initial&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#conclusion&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Conclusion”&quot;&gt;Conclusion&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;
</content:encoded><category>aspire</category><category>dotnet</category></item><item><title>Htmx and Playwright Tests in C#</title><link>https://khalidabuhakmeh.com/posts/htmx-and-playwright-tests-in-csharp/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/htmx-and-playwright-tests-in-csharp/</guid><description>Stop flaky waits in C# Playwright tests by listening for HTMX&apos;s afterSettle lifecycle event instead of guessing timeouts.</description><pubDate>Tue, 24 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&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;h2 id=&quot;the-htmx-counter-application&quot;&gt;&lt;a href=&quot;#the-htmx-counter-application&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “The Htmx Counter Application”&quot;&gt;The Htmx Counter Application&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;razor&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@model&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxPlaywrightIntegration&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ViewModels&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CounterViewModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;counter&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card-body&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Model.Count&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;card-footer&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;asp-page&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-post&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-target&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;#counter&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;hx-swap&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;outerHTML&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B;--0fs:italic&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;btn btn-primary&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;Increment&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@model HtmxPlaywrightIntegration.ViewModels.CounterViewModel&lt;div id=&amp;quot;counter&amp;quot; class=&amp;quot;card&amp;quot;&gt;    &lt;div id=&amp;quot;value&amp;quot; class=&amp;quot;card-body&amp;quot;&gt;        @Model.Count    &lt;/div&gt;    &lt;div class=&amp;quot;card-footer&amp;quot;&gt;        &lt;form asp-page=&amp;quot;Index&amp;quot; method=&amp;quot;post&amp;quot;              hx-post              hx-target=&amp;quot;#counter&amp;quot;              hx-swap=&amp;quot;outerHTML&amp;quot;&gt;            &lt;button class=&amp;quot;btn btn-primary&amp;quot;&gt;Increment&lt;/button&gt;        &lt;/form&gt;    &lt;/div&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The ASP.NET Core endpoint is straightforward.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxPlaywrightIntegration&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ViewModels&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;AspNetCore&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Mvc&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;RazorPages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxPlaywrightIntegration&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Pages&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;ILogger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IndexModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PageModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;CounterViewModel&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Value { &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnGet&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IActionResult&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;OnPost&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Value.Count &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Partial&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;_Counter&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, Value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using HtmxPlaywrightIntegration.ViewModels;using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.RazorPages;namespace HtmxPlaywrightIntegration.Pages;public class IndexModel(ILogger&lt;IndexModel&gt; logger) : PageModel{    public static CounterViewModel Value { get; set; }        = new();    public void OnGet()    {    }    public IActionResult OnPost()    {        Value.Count += 1;        return Partial(&amp;quot;_Counter&amp;quot;, Value);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#htmx-request-lifecycle-events&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Htmx Request Lifecycle Events”&quot;&gt;Htmx Request Lifecycle Events&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;document.body.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;htmx:afterSettle&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;evt&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;playwright:continue&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;document.body.addEventListener(&amp;#x27;htmx:afterSettle&amp;#x27;, function(evt) {    console.log(&amp;#x27;playwright:continue&amp;#x27;);});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;&lt;a href=&quot;#playwright-and-htmx-extensions&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Playwright and Htmx Extensions”&quot;&gt;Playwright and Htmx Extensions&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, let’s look at our test.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxPlaywrightIntegration&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Tests&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Parallelizable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(ParallelScope.Self)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;TestFixture&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;Tests&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;PageTest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Test&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;CanIncrementCountUsingHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GotoAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;http://localhost:5170&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RegisterHtmxLifecycleListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; button &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Locator&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;text=Increment&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; body &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Locator&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;#value&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; currentCount &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Parse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; body.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;TextContentAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;-1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; button.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ClickAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WaitForHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Expect&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(body).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToHaveTextAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;currentCount&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;namespace HtmxPlaywrightIntegration.Tests;[Parallelizable(ParallelScope.Self)][TestFixture]public class Tests : PageTest{    [Test]    public async Task CanIncrementCountUsingHtmx()    {        await Page.GotoAsync(&amp;quot;http://localhost:5170&amp;quot;);        await Page.RegisterHtmxLifecycleListener();        var button = Page.Locator(&amp;quot;text=Increment&amp;quot;);        var body = Page.Locator(&amp;quot;#value&amp;quot;);        var currentCount = int.Parse(await body.TextContentAsync() ?? &amp;quot;-1&amp;quot;);        await button.ClickAsync();        await Page.WaitForHtmx();        await Expect(body).ToHaveTextAsync($&amp;quot;{currentCount+1}&amp;quot;);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Microsoft&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Playwright&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;HtmxPlaywrightIntegration&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Tests&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;HtmxExtensions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Continue &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;playwright:continue&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WaitForHtmx&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IPage&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WaitForConsoleMessageAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Predicate &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; message.Text &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; Continue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;RegisterHtmxLifecycleListener&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IPage&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; page.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;AddScriptTagAsync&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#96A1C2&quot;&gt;// language=javascript&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Content &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$$&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;                      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;document.body.addEventListener(&apos;htmx:afterSettle&apos;, function(evt) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;                          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;console.log(&apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Continue&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;                      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                      &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;using Microsoft.Playwright;namespace HtmxPlaywrightIntegration.Tests;public static class HtmxExtensions{    private const string Continue = &amp;quot;playwright:continue&amp;quot;;    public static Task WaitForHtmx(this IPage page)    {        return page.WaitForConsoleMessageAsync(new() {            Predicate = message =&gt; message.Text == Continue        });    }    public static Task RegisterHtmxLifecycleListener(this IPage page)    {        return page.AddScriptTagAsync(new()        {            // language=javascript            Content = $$&amp;quot;&amp;quot;&amp;quot;                      document.body.addEventListener(&amp;#x27;htmx:afterSettle&amp;#x27;, function(evt) {                          console.log(&amp;#x27;{{Continue}}&amp;#x27;);                      });                      &amp;quot;&amp;quot;&amp;quot;        });    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;
</content:encoded><category>htmx</category><category>playwright</category></item><item><title>Intersperse Values for Enumerable Collections</title><link>https://khalidabuhakmeh.com/posts/intersperse-values-for-enumerable-collections/</link><guid isPermaLink="true">https://khalidabuhakmeh.com/posts/intersperse-values-for-enumerable-collections/</guid><description>Build a C# Intersperse extension method for IEnumerable that inserts a separator between elements, inspired by JavaScript&apos;s standard library.</description><pubDate>Tue, 10 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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; rel=&quot;noreferrer noopener&quot; target=&quot;_blank&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;h2 id=&quot;intersperse-implementation-in-c&quot;&gt;&lt;a href=&quot;#intersperse-implementation-in-c&quot; class=&quot;not-prose heading-anchor&quot; aria-label=&quot;Permalink to “Intersperse implementation in C#”&quot;&gt;Intersperse implementation in C#&lt;span class=&quot;heading-anchor-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;&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;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://khalidabuhakmeh.com/_astro/ec.wgrfz.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hello &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;-&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToArray&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; one &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;x&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToArray&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; @null &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToArray&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; array &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;[] { &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; }.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;ToArray&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; menu &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; [] {&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;Privacy&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Aggregate&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;&apos; interspersed with &apos;-&apos; is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;1 interspersed is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;one&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;null interspersed is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;@null&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;array interspersed is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Join&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;Console.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;$&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F1FA8C&quot;&gt;The menu is &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;menu&lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E9F284&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var hello = new string(&amp;quot;Hello&amp;quot;.Intersperse(&amp;#x27;-&amp;#x27;).ToArray());var one = new string(&amp;quot;1&amp;quot;.Intersperse(&amp;#x27;x&amp;#x27;).ToArray());var @null = ((IEnumerable&lt;object&gt;)null!).Intersperse(&amp;#x27;,&amp;#x27;).ToArray();var array = new[] { 1, 2, 3 }.Intersperse(42).ToArray();var menu = new [] {&amp;quot;Home&amp;quot;, &amp;quot;About&amp;quot;, &amp;quot;Privacy&amp;quot; }    .Intersperse(&amp;quot; &gt; &amp;quot;)    .Aggregate((a, b) =&gt; $&amp;quot;{a}{b}&amp;quot;);Console.WriteLine($&amp;quot;&amp;#x27;{hello}&amp;#x27; interspersed with &amp;#x27;-&amp;#x27; is {hello}&amp;quot;);Console.WriteLine($&amp;quot;1 interspersed is {one}&amp;quot;);Console.WriteLine($&amp;quot;null interspersed is {@null}&amp;quot;);Console.WriteLine($&amp;quot;array interspersed is {string.Join(&amp;quot;, &amp;quot;, array)}&amp;quot;);Console.WriteLine($&amp;quot;The menu is {menu}&amp;quot;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Running this application, we will see the following output.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;&apos;H-e-l-l-o&apos; interspersed with &apos;-&apos; is H-e-l-l-o&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;1 interspersed is 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;null interspersed is System.Object[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;array interspersed is 1, 42, 2, 42, 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#f8f8f2&quot;&gt;The menu is Home &amp;gt; About &amp;gt; Privacy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;#x27;H-e-l-l-o&amp;#x27; interspersed with &amp;#x27;-&amp;#x27; 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 &gt; About &gt; Privacy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s get to the implementation!&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD&quot;&gt;EnumerableExtensions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;Intersperse&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;IEnumerable&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;&amp;gt;? &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8BE9FD;--0fs:italic&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFB86C;--0fs:italic&quot;&gt;delimiter&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (source &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; enumerator &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; source.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;GetEnumerator&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; hasFirstElement &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; enumerator.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveNext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (hasFirstElement &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BD93F9&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; enumerator.Current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; (enumerator.&lt;/span&gt;&lt;span style=&quot;--0:#50FA7B&quot;&gt;MoveNext&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; delimiter;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF79C6&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt; enumerator.Current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F8F8F2&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public static class EnumerableExtensions{    public static IEnumerable&lt;T&gt; Intersperse&lt;T&gt;(        this IEnumerable&lt;T&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;        }    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&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;
</content:encoded><category>dotnet</category><category>csharp</category></item></channel></rss>