<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeffrey T. Fritz</title>
    <description>The latest articles on DEV Community by Jeffrey T. Fritz (@csharpfritz).</description>
    <link>https://dev.to/csharpfritz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F75581%2Fd83c202a-4fb7-4610-87da-c3690d235ac5.png</url>
      <title>DEV Community: Jeffrey T. Fritz</title>
      <link>https://dev.to/csharpfritz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/csharpfritz"/>
    <language>en</language>
    <item>
      <title>Blazor and .NET 8: How I Built a Fast and Flexible Website</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Thu, 22 Feb 2024 15:47:54 +0000</pubDate>
      <link>https://dev.to/csharpfritz/blazor-and-net-8-how-i-built-a-fast-and-flexible-website-5fll</link>
      <guid>https://dev.to/csharpfritz/blazor-and-net-8-how-i-built-a-fast-and-flexible-website-5fll</guid>
      <description>&lt;p&gt;I’ve been working on a new website for my series &lt;a href="https://csharpinthecards.com" rel="noopener noreferrer"&gt;CSharp in the Cards&lt;/a&gt;. I built this website in a way that was easy to maintain, flexible and most importantly would respond quickly to requests from visitors.  I knew that &lt;a href="https://blazor.net" rel="noopener noreferrer"&gt;Blazor with .NET 8&lt;/a&gt; had a static server rendering feature and decided that I wanted to put it to the test. I recently published a new lesson to the website and included a web assembly component to allow for paging and filtering the list of lessons I was pleasantly surprised when I saw the performance dashboards on azure showing that it was handling requests and responding very very quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jeffreyfritz.com/wp-content/uploads/2024/02/Screenshot-2024-02-20-152034.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjeffreyfritz.com%2Fwp-content%2Fuploads%2F2024%2F02%2FScreenshot-2024-02-20-152034.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Response times of C# in the Cards after the new episode&lt;/p&gt;

&lt;p&gt;In this blog post, let’s talk about how I’ve optimized the website for speed and some of the finishing touches that you can put on your Blazor website to make it screaming fast running on a very small instance of Azure App Service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Site Rendering – Its Blazor, but easier
&lt;/h2&gt;

&lt;p&gt;With .NET 8 there’s a new render mode for Blazor and it’s called static site rendering or SSR. This new render mode ditches all interactivity that we previously had with Blazor server side and Blazor Web Assembly and instead favors delivering HTML and other content from the server to browsers in a high speed manner. We can bolt on other techniques that we know from SEO and website optimization to make this even faster and deliver a great experience for our visitors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;@page "/About"
@attribute [OutputCache(Duration = 600)]

&lt;span class="nt"&gt;&amp;lt;PageTitle&amp;gt;&lt;/span&gt;C# in the Cards - About Us&lt;span class="nt"&gt;&amp;lt;/PageTitle&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;HeadContent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://csharpinthecards.com/about"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards - About Us"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards is an innovative video training series that teaches the fundamentals of C# programming language using a deck of cards. Join Microsoft instructor and Twitch streamer Jeff Fritz on this exciting journey."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"keywords"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C#, Programming, Learning, Video Series, Jeff Fritz, Microsoft, Twitch, Education, Coding, Deck of Cards, Interactive Learning"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"index, follow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards - About Us"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards is an innovative video training series that teaches the fundamentals of C# programming language using a deck of cards. Join Microsoft instructor and Twitch streamer Jeff Fritz on this exciting journey."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://csharpinthecards.com/img/jeff.webp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://csharpinthecards.com"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:site"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"@@csharpfritz"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards - About Us"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"C# in the Cards is an innovative video training series that teaches the fundamentals of C# programming language using a deck of cards. Join Microsoft instructor and Twitch streamer Jeff Fritz on this exciting journey."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://csharpinthecards.com/img/jeff.webp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/HeadContent&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;About C# in the Cards&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://csharpinthecards.com/about" rel="noopener noreferrer"&gt;About page&lt;/a&gt; is configured to output a bunch of HTML headers for the SEO folks and the social media pages to be able to present good information about the site.  Notice the headers that are added to satisfy the search engines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a canonical link element that identifies where the page should be served from&lt;/li&gt;
&lt;li&gt;a keywords meta element with information about what you can find here&lt;/li&gt;
&lt;li&gt;a robots element that tells the search engine crawlers what they can do with the page&lt;/li&gt;
&lt;li&gt;open graph and Twitter meta tags that instruct Twitter, Facebook, LinkedIn, Discord, and other sites about the images, titles, and description of the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s fine… but there are two other features to notice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This is a static page with no data being presented.  I’ve tagged it on line 2 with an attribute to allow output caching for 600 seconds (10 minutes).  This way the web server doesn’t have to render a new copy when its requested within 10 minutes of a previous request.&lt;/li&gt;
&lt;li&gt;The images references are in webp format.  Let’s not overlook this super-compressed format for displaying high-quality images.  It might be 2024, but every bit we deliver over the network still matters for performance and the 600×600 portrait picture of myself on this page was compressed nicely:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original&lt;/th&gt;
&lt;th&gt;Compressed&lt;/th&gt;
&lt;th&gt;# Difference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PNG&lt;/td&gt;
&lt;td&gt;WEBP&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;450kb&lt;/td&gt;
&lt;td&gt;30kb&lt;/td&gt;
&lt;td&gt;-93.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;93% savings…  that’s crazy good and means that your browser is not downloading an extra 420kb it doesn’t need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data is stored in static files on disk
&lt;/h2&gt;

&lt;p&gt;For this simple website I don’t need a big fancy database like SQL Server or Postgres or even MySQL. For this site, I’ve stored all of the data in a simple CSV file on disk.  That means that I can edit the list of articles that are available and the metadata that goes with them by just opening the file in Excel and writing new content. This means that when it comes time for me to read data about the list of content that’s available I’m only reading from a very small file on disk and I don’t need to worry about any kind of contention. I also don’t need to worry about any service that’s running to deliver that data because it’s only coming out of a small file on disk that’s read only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IWebHostEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_Cache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IHostEnvironment&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;POST_CACHE_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"post_data"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;_Cache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PostModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPostsFromDisk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// open the posts.csv file from the wwwroot folder using linq2csv&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LINQtoCSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CsvContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentRootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"wwwroot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"posts.csv"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CsvFileDescription&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;SeparatorChar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;FirstLineHasColumnNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;QuoteAllFields&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;UseFieldIndexForReadingData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;IgnoreUnknownColumns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PostModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;PostModel&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GetPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_Cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOrCreate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PostModel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POST_CACHE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlidingExpiration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;GetPostsFromDisk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;})!;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this repository class I use the &lt;a href="https://www.nuget.org/packages/LinqToCsv" rel="noopener noreferrer"&gt;LinqToCSV library&lt;/a&gt; to open and read all of the content from the file into a Post object in the first method, GetPostsFromDisk.  Later, in a public method called GetPosts, you see where I use the in memory cache feature of ASP.NET Core to fetch data from the cache if its available or get it from disk and store it in cache for 30 minutes.  I could probably extend this timeout to several hours or even days since the website doesn’t get any new content without uploading a new version of the site.&lt;/p&gt;

&lt;p&gt;The key here is that the meta data about the lessons on the site is loaded and kept in memory.  As of episode 9 of the series, the posts.csv file is only 1.4kb so I have no worries about loading its entire contents into memory.&lt;/p&gt;

&lt;p&gt;Don’t forget, in order to add the MemoryCache to your ASP.NET Core application, you need to add this line to your site configuration in the Program.cs file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddMemoryCache();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I could add other cache options like Redis to the site, but with how small the data I want to cache is, I don’t need that sophistication at this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-rendered Interactive Web Assembly Content is fast… REALLY fast
&lt;/h2&gt;

&lt;p&gt;I wanted to add a subset of the lessons to the front page of the website so that you could see the latest six episodes in the video series and scroll back and forth to the other episodes. This should be an interactive component but I still wanted the home page to render quickly and have a fresh speedy response time as you page through and look at the various episodes that are available. The natural way to do this with Blazor is to build a web assembly component that will run on the client and render data as users click on the buttons for that collection of articles.&lt;/p&gt;

&lt;p&gt;I wrote a simple pager component that would receive a collection of lesson data and render cards for each lesson.  Since we already know that the collection of lesson data is less than 2kb in size I don’t have a problem sending the entire collection of data into the browser to be rendered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Recent Lessons&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PagingPostCollection&lt;/span&gt; 
  &lt;span class="na"&gt;Posts=&lt;/span&gt;&lt;span class="s"&gt;"Posts"&lt;/span&gt; &lt;span class="na"&gt;PageSize=&lt;/span&gt;&lt;span class="s"&gt;"6"&lt;/span&gt; 
  &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;rendermode=&lt;/span&gt;&lt;span class="s"&gt;"InteractiveWebAssembly"&lt;/span&gt;
  &lt;span class="na"&gt;SortAscending=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I use the @rendermode attribute in this code, it forces the render mode to web assembly and ASP.NET will pre-render as well as cache a version of that component’s resultant HTML with the home page. After viewers download the Web Assembly content it will hand control over to web assembly and it will be a fully interactive component for them to be able to work with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jeffreyfritz.com/wp-content/uploads/2024/02/pager.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjeffreyfritz.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fpager-300x188.png" alt="Lesson Pager on the C# in the Cards website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lesson Pager on the C# in the Cards website&lt;/p&gt;

&lt;p&gt;Blazor lets me build content to be rendered on the web and I get to choose where exactly it should run. It can run in the browser with web assembly it can run statically on the server it can run interactively on the server if I want it to. In this case running as web assembly gives a really nice usability effect that makes it easy for viewers to locate the content they want to watch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compress the Content from Kestrel
&lt;/h2&gt;

&lt;p&gt;By default content that’s delivered from the ASP.NET kestrel web server is uncompressed. We can add brotli compression to the Web server and deliver content in a much smaller package to our visitors with just a few simple lines of code in program.cs. This is something that I think everybody should do with their Internet facing websites:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#if (!DEBUG)
builder.Services.AddResponseCompression(options =&amp;gt;
{
options.EnableForHttps = true;
});
#endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add response compression configures the server so that it will deliver broadly compressed content. In this application I wrap it with the conditional debug detection because hot reload does not work with compression enabled.  When we deliver the website to the production web host it will be running in release mode and compression will be enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize all the JavaScript and CSS
&lt;/h2&gt;

&lt;p&gt;CSS AND JavaScript can be minified and combined to reduce the number and size of downloads for this static content that makes our websites look good.  For this website I installed and used the &lt;a href="https://www.nuget.org/packages/LigerShark.WebOptimizer.Core" rel="noopener noreferrer"&gt;WebOptimizer package&lt;/a&gt; available on NuGet.  My configuration for this looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWebOptimizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCssBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/css/bundle.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;NUglify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CssSettings&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CommentMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NUglify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CssComment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s"&gt;"app.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"css/bootstrap.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s"&gt;"css/plugins.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"css/colors.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"css/responsive.css"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MinifyJsFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/js/jqueryCustom.js"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script bundles the CSS files that were delivered with my website template and minifies the one JavaScript file that I manage with my project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set long cache-control headers for static content
&lt;/h2&gt;

&lt;p&gt;The last thing that I did was set long duration cash dash control headers for static content like images CSS and Javascript files. This is easy to do with just a few more lines of optional configuration when I configure the static file feature inside of ASP.NET Core:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseStaticFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StaticFileOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;OnPrepareResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PhysicalPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".css"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".js"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; 
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".gif"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".jpg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; 
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".svg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".webp"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;TimeSpan&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;370&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache-Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"max-age="&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalSeconds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This website’s been easy for me to build because I can rely on my normal HTML skills and the plethora of HTML templates and CSS libraries out there to make my website look good. &lt;a href="https://blazor.net" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt; helps me to make it interactive render quickly and grow as I add more content to it. my cost in interaction with azure is minimal, as I’m using a &lt;a href="https://azure.microsoft.com/en-us/pricing/details/app-service/linux/" rel="noopener noreferrer"&gt;Basic-2 instance of Azure App Service running Linux&lt;/a&gt; to deliver this site.&lt;/p&gt;

</description>
      <category>web</category>
      <category>dotnet</category>
      <category>azure</category>
      <category>blazor</category>
    </item>
    <item>
      <title>I built an Android app on my Linux machine using .NET 7 and MAUI</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Sun, 04 Dec 2022 03:04:08 +0000</pubDate>
      <link>https://dev.to/csharpfritz/i-built-an-android-app-on-my-linux-machine-using-net-7-and-maui-41if</link>
      <guid>https://dev.to/csharpfritz/i-built-an-android-app-on-my-linux-machine-using-net-7-and-maui-41if</guid>
      <description>&lt;p&gt;I’ve been tinkering and preparing to build a mobile app for the &lt;a href="https://kliptok.com" rel="noopener noreferrer"&gt;KlipTok website&lt;/a&gt; for the past few months. KlipTok is a personal project, and a joy to work on when I have an hour here and there to spend on the site. The most requested feature I have, is for a mobile app to complement the site, and this week I started focusing on that effort… and was even able to build an Android app using .NET MAUI, Blazor, and my Linux laptop. In this post, I’ll describe how I went about getting the development environment working on Ubuntu Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  NOTE: Your experience might be different
&lt;/h3&gt;

&lt;p&gt;Every Linux system is different, and I can point you in the direction that worked for me.  I cannot guarantee that you will find similar success or answer questions for your configuration.&lt;/p&gt;

&lt;p&gt;I started this project on my Twitch stream on Friday December 2nd, and was able to get a simple Blazor MAUI application that played a Twitch clip running on my Windows machine.  I used Visual Studio 2022 and the Android emulator that came with it and was happy to have an initial proof-of-concept application running.&lt;/p&gt;

&lt;p&gt;I prefer to use my Linux laptop from KFocus when I am not in my home office. It’s a great machine with plenty of power for development. With a quick web search, I found an article where someone was setting up &lt;a href="https://rjj-software.co.uk/blog/building-net-maui-android-apps-on-linux-based-operating-systems/" rel="noopener noreferrer"&gt;Android development on Linux&lt;/a&gt;.  I read through those steps, updated to .NET 7, and wrote a few scripts to help with my development.  Here’s what I did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I installed Android Studio from the Ubuntu app repository using the Discover app.&lt;/li&gt;
&lt;li&gt;I opened Android Studio and grabbed the SDK folder from the Android SDK Manager tool, depicted below.  In my case, its sitting in /home/csharpfritz/Android/Sdk.  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkogxgaa4zso8w27mfmaz.png" alt="Android Studio SDK Manager screen" width="800" height="532"&gt;
&lt;/li&gt;
&lt;li&gt;Installed the .NET MAUI workload into .NET 7 at the command-line with the command: &lt;code&gt;sudo dotnet workload install maui-android&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Installed the Android Debug Bridge (ADB) with &lt;code&gt;sudo apt install adb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Started and ran the emulator from Android Studio, verifying that it was running with &lt;code&gt;adb devices&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdsnz6ed0gfvu3a2lzaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdsnz6ed0gfvu3a2lzaf.png" alt="Android Emulator running on Linux" width="147" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that I have the emulator running, I could build and deploy my application to the emulator with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet build -t:Run -f net7.0-android /p:AndroidSdkDirectory=/home/csharpfritz/Android/Sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first test, it failed miserably and complained about not supporting MacCatalyst and iOS development on Linux.  Not a problem, so I updated the csproj file to have supported frameworks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;TargetFrameworks&amp;gt;net7.0-android;&amp;lt;/TargetFrameworks&amp;gt;
&amp;lt;TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('osx'))"&amp;gt;
  $(TargetFrameworks);net7.0-ios;net7.0-maccatalyst
&amp;lt;/TargetFrameworks&amp;gt;
&amp;lt;TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))"&amp;gt;
  $(TargetFrameworks);net7.0-windows10.0.19041.0
&amp;lt;/TargetFrameworks&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I now build on Linux, just the Android configuration runs.  This also means I can drop the -f argument in the command-line.  I tried to recompile and got errors about the compiler not finding the Java jar tool.  Easy enough, I installed the latest tool with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install openjdk-11-jdk-headless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I compiled and was able to deploy to the emulator in 55 seconds!  Progress!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqv1aunxsjsaqz3qh0mk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqv1aunxsjsaqz3qh0mk.png" alt="KlipTok running on an Android emulator on LInux" width="422" height="863"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last steps, I wanted to get the app building and recompiling with dotnet watch.  This way, I can make changes and the app will reflect those changes in the emulator.  My dotnet watch command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet watch build -t:Run /p:AndroidSdkDirectory=/home/csharpfritz/Android/Sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I found that the app didn’t rebuild and deploy when I made changes to the razor files.  Easy enough, I made another addition to my csproj file to include a definition for watching the razor files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Watch Include="**\*.razor" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this patched, I was able to build and run the app in watch mode.  As I changed razor files, the app would redeploy to the emulator in 6 seconds!  That’s such a better development experience.  Last thing that I tried, was to add a switch to my script to shut off the analyzers when I’m in watch mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet watch build -t:Run /p:AndroidSdkDirectory=/home/csharpfritz/Android/Sdk /p:RunAnalyzers=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That didn’t give me a big boost in performance, but I feel better without the analyzers running when I’m in watch mode.&lt;/p&gt;

&lt;p&gt;Have you tried building an Android app on Linux with MAUI?  Do you have any tips or tricks for developers to use in order to have a better experience?  Share with us in the comments below&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>linux</category>
      <category>android</category>
    </item>
    <item>
      <title>Build APIs for the Web INSTANTLY with ASP.NET Core 6</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Wed, 23 Feb 2022 19:19:19 +0000</pubDate>
      <link>https://dev.to/dotnet/build-apis-for-the-web-instantly-with-aspnet-core-6-30lc</link>
      <guid>https://dev.to/dotnet/build-apis-for-the-web-instantly-with-aspnet-core-6-30lc</guid>
      <description>&lt;p&gt;I've been building web-based applications for many years, and I always run into the same questions and code that needs to be written again and again.  How do we get data into and out of the database for 90% of our interactions?  The simple create, read, update, and delete operations... we've simplified those processes over time with ORM tools like NHibernate, Entity Framework, and Dapper.  The next question is, how do we get that data into our applications easily?  We want to create a repeatable process that is easy to follow and quick to integrate.&lt;/p&gt;

&lt;p&gt;Typically, folks have been building some sort of API that a web server responds with.  Great, now we have to write ANOTHER layer of code over the database and generate records for all of those things we just exposed to our application with an ORM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Minimal APIs
&lt;/h2&gt;

&lt;p&gt;In ASP.NET Core 6, we can dramatically simplify the creation of these APIs for interaction with the database by using the new Minimal API approach.  Our API code can be delivered in 1 file, referencing the Entity Framework context that connects to the database.&lt;/p&gt;

&lt;p&gt;Consider this configuration to expose a &lt;code&gt;Contacts&lt;/code&gt; table as a web endpoint that can be accessed with an HTTP GET verb:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSqlite&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"Data Source=contacts.db"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/Contacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArrayAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/Contacts/{id:int}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's still a LOT of boilerplate code to just generate the GET and GET by id actions.  We still have 3 more methods to write, and that's just for this first entity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate the code... do it in 1 line
&lt;/h2&gt;

&lt;p&gt;This got me thinking, and I wanted to make this easier to build with sensible defaults.  I put together a simple prototype that would generate ALL 5 of the default HTTP actions with a NuGet package and 1 line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSqlite&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"Data Source=contacts.db"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapInstantAPIs&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're talking!  This one statement generates the following HTTP endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET &lt;code&gt;/api/Contact&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GET &lt;code&gt;/api/Contact/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;POST &lt;code&gt;/api/Contact&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PUT &lt;code&gt;/api/Contact/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DELETE &lt;code&gt;/api/Contact/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put together a demo discussing this library and showing how it generates the same code that you might write by hand:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/vCSWXAOEpBo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is still just a prototype, but if you would like to learn more, check out our &lt;a href="https://github.com/csharpfritz/InstantAPIs"&gt;GitHub repository&lt;/a&gt; where we are welcoming discussions and pull requests. You can even try out the library yourself by downloading the &lt;a href="https://www.nuget.org/packages/Fritz.InstantAPIs/"&gt;latest NuGet package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How are you building APIs for the web?  How would you like to see it made easier and more repeatable?&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>web</category>
      <category>api</category>
    </item>
    <item>
      <title>My Favorite C# Features - Part 5: Build for the Modern Web with Blazor</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Fri, 20 Aug 2021 16:15:55 +0000</pubDate>
      <link>https://dev.to/dotnet/my-favorite-c-features-part-5-build-for-the-modern-web-with-blazor-29b1</link>
      <guid>https://dev.to/dotnet/my-favorite-c-features-part-5-build-for-the-modern-web-with-blazor-29b1</guid>
      <description>&lt;p&gt;I've written a bit about the various language features that I really like about C# over the last few months, but today I'm going to pivot slightly and talk about how much fun it is to write web applications with the Blazor web framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Blazor?
&lt;/h2&gt;

&lt;p&gt;Blazor is a modern component-based web framework that is built on top of the .NET runtime and can run on either a web server OR in a browser using Web Assembly.  Blazor was introduced as an experiment by Steve Sanderson at NDC Oslo in 2017:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/MiLAE6HMr10"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This initial simple concept for building and running C# and .NET code in the browser as a "new SPA framework" captured the imaginations of .NET developers.  After 2 years of experimentation and exploration by the .NET engineering team, Blazor became an official .NET framework with Web Assembly and Server hosted versions available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Assembly AND Server version?
&lt;/h3&gt;

&lt;p&gt;Blazor gives developers a way to define components and pages using C# with &lt;a href="https://docs.microsoft.com/aspnet/core/mvc/views/razor?view=aspnetcore-5.0" rel="noopener noreferrer"&gt;Razor templates&lt;/a&gt;.  What if you really like the Blazor technology, but don't want to deliver and run the content in the browser using Web Assembly?  Maybe you have some code that you need to ensure is run in a validated and protected server-based environment, well you can do that with Blazor Server-Side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdua2abgo4lhricwdp4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdua2abgo4lhricwdp4j.png" alt="Blazor Server-Side Framework Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this model, Blazor pages and components are rendered on the server and delivered to the web browser using web sockets and more specifically the &lt;a href="https://docs.microsoft.com/aspnet/core/tutorials/signalr?view=aspnetcore-5.0" rel="noopener noreferrer"&gt;SignalR framework&lt;/a&gt;.  All interactions in the browser are transmitted to the server over a SignalR connection (typically an abstraction over web sockets) and the rendered HTML is returned and updated by the Blazor Server-Side framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I get started?
&lt;/h2&gt;

&lt;p&gt;Blazor is part of the .NET toolset.  You can get started by headed to &lt;a href="https://blazor.net" rel="noopener noreferrer"&gt;https://blazor.net&lt;/a&gt; and installing the .NET command-line tools or Visual Studio.  I have a &lt;a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oUJCA3DCzKT79Oe3kdKEceX" rel="noopener noreferrer"&gt;new playlist of videos&lt;/a&gt; that will walk you through some simple scenarios that you can find on YouTube:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9BhbGbTsyeE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Page
&lt;/h2&gt;

&lt;p&gt;A simple Blazor page that can be used to fetch some data from an HTTP-based API can be queried and its contents displayed with a Blazor page like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@page "/fetchdata"
@inject HttpClient Http

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Weather forecast&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This component demonstrates fetching data from the server.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

@if (forecasts == null)
{
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
}
else
{
    &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Date&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Temp. (C)&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Temp. (F)&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Summary&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            @foreach (var forecast in forecasts)
            {
                &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;@forecast.Date.ToShortDateString()&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;@forecast.TemperatureC&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;@forecast.TemperatureF&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;@forecast.Summary&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
            }
        &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
}

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await Http.GetFromJsonAsync&lt;span class="nt"&gt;&amp;lt;WeatherForecast&lt;/span&gt;&lt;span class="err"&gt;[]&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;("sample-data/weather.json");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the basic FetchData sample that is delivered in the Blazor templates.  It shows the following techniques in building a Blazor page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining that this is a page with an address to be routed to using the &lt;code&gt;@page&lt;/code&gt; directive on the first line.&lt;/li&gt;
&lt;li&gt;Injecting an &lt;code&gt;HttpClient&lt;/code&gt; named &lt;code&gt;Http&lt;/code&gt; with the &lt;code&gt;@inject&lt;/code&gt; directive on the second line.  The &lt;code&gt;HttpClient&lt;/code&gt; is later used to get data in JSON format and convert it to an array of &lt;code&gt;WeatherForecast&lt;/code&gt; objects to be painted on screen.&lt;/li&gt;
&lt;li&gt;Emitting some standard table HTML tags with a for-loop across our collection of weather forecasts.  The C# code in a Razor template is denoted by the &lt;code&gt;@&lt;/code&gt; character&lt;/li&gt;
&lt;li&gt;Handling the OnInitializedAsync event on the page to load data when the Blazor runtime initializes the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Community Support and Interactions
&lt;/h2&gt;

&lt;p&gt;There is a growing and enthusiastic community of Blazor developers, projects, and companies building tools and samples for Blazor.  Check out the Awesome Blazor list on GitHub to see more:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AdrienTorris" rel="noopener noreferrer"&gt;
        AdrienTorris
      &lt;/a&gt; / &lt;a href="https://github.com/AdrienTorris/awesome-blazor" rel="noopener noreferrer"&gt;
        awesome-blazor
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Resources for Blazor, a .NET web framework using C#/Razor and HTML that runs in the browser with WebAssembly.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Awesome Blazor &lt;a href="https://awesome.re" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f4534299c4fb07eccb37b82d3e7aa23cb225094b2dd2a311be7c4b9779c3ed8/68747470733a2f2f617765736f6d652e72652f62616467652d666c6174322e737667" alt="Awesome"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/client" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c8be5d4727c3823912c2542cb48d9b21ce5ec48697256ff18a6391bc7847bc29/68747470733a2f2f61647269656e746f727269732e6769746875622e696f2f777777726f6f742f696d616765732f626c617a6f722f6c6f676f2d626c617a6f722e706e67" width="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A collection of awesome Blazor resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Blazor is a .NET web framework using C#/Razor and HTML that runs in the browser with WebAssembly.&lt;/p&gt;

&lt;p&gt;Contributions are always welcome! Please take a look at the &lt;a href="https://github.com/AdrienTorris/awesome-blazor/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contribution guidelines&lt;/a&gt; pages first. Thanks to all &lt;a href="https://github.com/AdrienTorris/awesome-blazor/graphs/contributors" rel="noopener noreferrer"&gt;contributors&lt;/a&gt;, you're awesome and wouldn't be possible without you!&lt;/p&gt;

&lt;p&gt;If you need to search on this list you can try this great website: &lt;a href="https://jsakamoto.github.io/awesome-blazor-browser/" rel="nofollow noopener noreferrer"&gt;Awesome Blazor Browser&lt;/a&gt;
Thanks &lt;a class="mentioned-user" href="https://dev.to/jsakamoto"&gt;@jsakamoto&lt;/a&gt; for this! &lt;a href="https://github.com/jsakamoto/awesome-blazor-browser" rel="noopener noreferrer"&gt;Source code&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a4cf9590e8c0cbbfad814551cd1622c954d8ca4cf98b40b10bff88eedaf9ee6b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6a73616b616d6f746f2f617765736f6d652d626c617a6f722d62726f777365723f7374796c653d666c61742d7371756172652663616368655365636f6e64733d363034383030"&gt;&lt;img src="https://camo.githubusercontent.com/a4cf9590e8c0cbbfad814551cd1622c954d8ca4cf98b40b10bff88eedaf9ee6b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6a73616b616d6f746f2f617765736f6d652d626c617a6f722d62726f777365723f7374796c653d666c61742d7371756172652663616368655365636f6e64733d363034383030" alt="stars"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/045755aec05840ce1a976005497e6df0f840568707f70d9daf8bb71df3fcf410/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a73616b616d6f746f2f617765736f6d652d626c617a6f722d62726f777365723f7374796c653d666c61742d7371756172652663616368655365636f6e64733d3836343030"&gt;&lt;img src="https://camo.githubusercontent.com/045755aec05840ce1a976005497e6df0f840568707f70d9daf8bb71df3fcf410/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a73616b616d6f746f2f617765736f6d652d626c617a6f722d62726f777365723f7374796c653d666c61742d7371756172652663616368655365636f6e64733d3836343030" alt="last commit"&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#introduction" rel="noopener noreferrer"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#general" rel="noopener noreferrer"&gt;General&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#templates" rel="noopener noreferrer"&gt;Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#sample-projects" rel="noopener noreferrer"&gt;Sample Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#tutorials" rel="noopener noreferrer"&gt;Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#libraries--extensions" rel="noopener noreferrer"&gt;Libraries &amp;amp; Extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#source-generators" rel="noopener noreferrer"&gt;Source generators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#real-world-applications" rel="noopener noreferrer"&gt;Real-World applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#videos" rel="noopener noreferrer"&gt;Videos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#articles" rel="noopener noreferrer"&gt;Articles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#podcasts" rel="noopener noreferrer"&gt;Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#presentations-slides" rel="noopener noreferrer"&gt;Presentations slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#tooling" rel="noopener noreferrer"&gt;Tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#books" rel="noopener noreferrer"&gt;Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#e-books" rel="noopener noreferrer"&gt;E-Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#courses" rel="noopener noreferrer"&gt;Courses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#community" rel="noopener noreferrer"&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AdrienTorris/awesome-blazor#other-languages" rel="noopener noreferrer"&gt;Other Languages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;What is Blazor?&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Blazor is a .NET web framework to build client web apps with C#.&lt;/p&gt;
&lt;p&gt;Blazor lets you build interactive web UIs using C# instead of JavaScript. Blazor apps are composed of reusable web UI components implemented using C#, HTML, and CSS. Both client and…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AdrienTorris/awesome-blazor" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Building web applications with Blazor is a great way for developers who enjoy C# and .NET to create interactive web applications.  I encourage you to check out the &lt;a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oUJCA3DCzKT79Oe3kdKEceX" rel="noopener noreferrer"&gt;Blazor 101 video series&lt;/a&gt; published on YouTube and check out &lt;a href="https://blazor.net" rel="noopener noreferrer"&gt;https://blazor.net&lt;/a&gt; for more learning materials and the tools to get started with Blazor.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
      <category>blazor</category>
    </item>
    <item>
      <title>My Favorite C# Features - Part 4: Project Structure</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Wed, 12 May 2021 14:25:36 +0000</pubDate>
      <link>https://dev.to/dotnet/my-favorite-c-features-part-4-project-structure-454p</link>
      <guid>https://dev.to/dotnet/my-favorite-c-features-part-4-project-structure-454p</guid>
      <description>&lt;p&gt;I've discussed several of my favorite features of the C# programming language in the previous few posts, but a question that I have heard on my Twitch stream and on Twitter is: "how should we best structure our projects to take advantage of these awesome features?"&lt;/p&gt;

&lt;p&gt;Oh the architecture questions.  There are many ways to structure your projects and solutions, and that volume of choices is part of what makes C# and .NET in general so amazing:  we get to be artists for a bit and design our source code structure in a way to makes us happy.&lt;/p&gt;

&lt;p&gt;In this post, I'll share some of the ways that I like to structure my projects and solutions as they evolve.  This is NOT a 'best practices' or required set of techniques for anyone to build an application system.  This is the way that I build systems that makes me happy, and maybe you'll find some of these techniques valuable in your systems as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  C# File Structure
&lt;/h2&gt;

&lt;p&gt;The C# language documentation has some great recommendations for &lt;a href="https://docs.microsoft.com/dotnet/csharp/programming-guide/inside-a-program/coding-conventions" rel="noopener noreferrer"&gt;standard conventions&lt;/a&gt; around naming, layout, and commenting.  However, they don't answer the question: "how should I structure the content of my C# code file?"&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1201.md" rel="noopener noreferrer"&gt;rule that StyleCop uses that will encourage you to order the contents of your C# files&lt;/a&gt; (*.cs) as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extern Alias Directives&lt;/li&gt;
&lt;li&gt;Using Directives&lt;/li&gt;
&lt;li&gt;Namespaces&lt;/li&gt;
&lt;li&gt;Delegates&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;li&gt;Interfaces&lt;/li&gt;
&lt;li&gt;Structs&lt;/li&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Within a class, struct, or interface the elements should be position in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fields&lt;/li&gt;
&lt;li&gt;Constructors&lt;/li&gt;
&lt;li&gt;Finalizers (Destructors)&lt;/li&gt;
&lt;li&gt;Delegates&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;li&gt;Interfaces&lt;/li&gt;
&lt;li&gt;Properties&lt;/li&gt;
&lt;li&gt;Indexers&lt;/li&gt;
&lt;li&gt;Methods&lt;/li&gt;
&lt;li&gt;Structs&lt;/li&gt;
&lt;li&gt;Nested Classes or Records&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can add the &lt;a href="https://www.nuget.org/packages/StyleCop.Analyzers" rel="noopener noreferrer"&gt;StyleCop Analyzers&lt;/a&gt; to your projects by simply adding a reference to the NuGet package "StyleCop.Analyzers".  On every build after installing these analyzers, you will get a report of the recommended changes to your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;As I start building a new system, the projects that comprise that system are typically all managed within the same solution file.  In rare cases, multiple solution files can be used to manage various logical segments of the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Naming
&lt;/h3&gt;

&lt;p&gt;As a web developer first, I like to typically start a new system by creating my initial application and name it the same as my Solution:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

- FritzsCoolApplication.sln
  - FritzsCoolApplication


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

&lt;/div&gt;

&lt;p&gt;I've learned over the many applications that I've created that this application is going to grow, shift, and change.  I've started postfixing my initial web application names with &lt;code&gt;.Web&lt;/code&gt; as they represent the web application that will be delivered.&lt;/p&gt;

&lt;p&gt;Additional projects that are added to the solution typically have the same base-name and have a suffix to indicate their purpose.  It's common to see projects in my solutions with names like:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;FritzsCoolApplication.Web&lt;br&gt;
FritzsCoolApplication.Api&lt;br&gt;
FritzsCoolApplication.BackOffice&lt;br&gt;
FritzsCoolApplication.Common&lt;br&gt;
FritzsCoolApplication.Core&lt;br&gt;
FritzsCoolApplication.Client&lt;br&gt;
FritzsCoolApplication.Communication&lt;br&gt;
FritzsCoolApplication.Proxy&lt;br&gt;
FritzsCoolApplication.Migrate&lt;br&gt;
FritzsCoolApplication.Test&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Folder Structure&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Folders in some projects are defined with conventions for use in making applications like ASP.NET MVC work without adding configuration.  This convention over configuration means the same folders are defined in these projects that we're going to find regardless of the direction of the project.  Consider the conventional folders for an MVC project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40cbx2i2enrgpir1ea30.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40cbx2i2enrgpir1ea30.PNG" alt="ASP.NET Core - MVC Project Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Controllers&lt;/code&gt;, &lt;code&gt;Models&lt;/code&gt;, and &lt;code&gt;Views&lt;/code&gt; folders are where the heart of the MVC application operates.  In all ASP.NET Core applications, the &lt;code&gt;wwwroot&lt;/code&gt; folder is where static files are kept that are served without server interpretation.  The default &lt;code&gt;css&lt;/code&gt;, &lt;code&gt;js&lt;/code&gt;, and &lt;code&gt;lib&lt;/code&gt; folders are a good standard for organizing CSS and JavaScript files.  Add an &lt;code&gt;img&lt;/code&gt; folder and a &lt;code&gt;fonts&lt;/code&gt; folder as needed for images and fonts and you have a great configuration for your web project.&lt;/p&gt;

&lt;p&gt;In a Razor Pages project, we see the replacement of the &lt;code&gt;Controllers&lt;/code&gt;, &lt;code&gt;Models&lt;/code&gt;, and &lt;code&gt;Views&lt;/code&gt; folders with a single &lt;code&gt;Pages&lt;/code&gt; folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next Folders to introduce
&lt;/h3&gt;

&lt;p&gt;Data interactions in the project typically start with a &lt;code&gt;Data&lt;/code&gt; folder and a potential &lt;code&gt;Migrations&lt;/code&gt; folder that is &lt;a href="https://docs.microsoft.com/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli" rel="noopener noreferrer"&gt;maintained by Entity Framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If I'm creating a hosted service, that is something that will be running as a background process inside my application, I will create a &lt;code&gt;Services&lt;/code&gt; folder in the project to contain these application specific processes.&lt;/p&gt;

&lt;p&gt;ViewModels are another concern, as we begin to constrain the contents presented and interacting with our web application.  These contents could be stored in a &lt;code&gt;ViewModels&lt;/code&gt; folder with appropriate conventions defined for working with user data.  This is also a great convention to use for interacting with our Web APIs that we may define in a project, especially if we want to introduce a front-end API framework like gRPC or OpenAPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing Unit Testing
&lt;/h3&gt;

&lt;p&gt;When significant business logic enters my application, I start to introduce unit tests.  By business logic, I am referring to more than the simple create, read, update, and delete operations with a database.  This logic is the programming model that you are introducing to calculate and provide those features that define your application.&lt;/p&gt;

&lt;p&gt;I prefer starting a second project next to my initial web application with a &lt;code&gt;Test&lt;/code&gt; suffix like &lt;code&gt;FritzsCoolApplication.Test&lt;/code&gt;.  I'll even go a step further and configure solution folders to place the test project in a location at the bottom of the Solution Explorer in Visual Studio, making it easier for me to find the test project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywwyxmhudbewsx7atzxj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywwyxmhudbewsx7atzxj.PNG" alt="Solution Folders with Unit Test project introduced"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolving From Folders to Projects
&lt;/h3&gt;

&lt;p&gt;As the complexity of our application grows, we want to introduce interfaces and abstractions to provide for re-use.  This is when I begin to introduce new projects that can be shared so that each project is a smaller and more manageable unit.&lt;/p&gt;

&lt;p&gt;The first project I typically introduce is a Class Library built with .NET Standard 2.0 named &lt;code&gt;.Core&lt;/code&gt; or &lt;code&gt;.Common&lt;/code&gt; and contains a collection of shared Enums, Constants, and Interfaces that I might be using across projects.  This project typically does not contain any executable code, but rather contains the definitions of cross-cutting features in use throughout the application system.&lt;/p&gt;

&lt;p&gt;Why make this project .NET Standard 2.0?  These features that I am defining are simple and I want maximum compatibility across all future projects.  &lt;a href="https://docs.microsoft.com/dotnet/standard/net-standard" rel="noopener noreferrer"&gt;.NET Standard 2.0 provides all of the flexibility&lt;/a&gt; that I need if I want to target Windows, Azure, Xamarin, .NET Core and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmvkw5z08w0zn7lrxvdo.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmvkw5z08w0zn7lrxvdo.PNG" alt="Adding the Common project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the number of resources in each folder of my initial web project grow and additional executables or services need to be hosted, I begin to separate each of those folders into their own projects that new executable or service projects can share.&lt;/p&gt;

&lt;p&gt;As new services for business domains are defined and added, I introduce a third segment to my project naming scheme that defines that domain.  The below image shows how I would introduce a pair of services that manage the Accounting and Inventory domains for my solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16b8wfv77xbviz0vwdwc.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16b8wfv77xbviz0vwdwc.PNG" alt="Adding Domain Specific Services"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary... for now
&lt;/h2&gt;

&lt;p&gt;The flexibility with which you can grow your application from a simple website or desktop application into an entire enterprise scale service is only limited by your imagination.  A few rules of thumb and guideposts along the way as you grow your application will help prevent project-sprawl with hundreds of little projects that don't add significant re-use or value to your solution, but instead create maintenance headaches.&lt;/p&gt;

&lt;p&gt;Don't be afraid to refactor mercilessly.  Content that starts to be re-used should move into shared projects and libraries that domains can re-use and end-user applications or websites can consume easily.  Your unit-tests are your friend and can help guarantee that your projects continue functioning at a high-level.&lt;/p&gt;

&lt;p&gt;How do you grow your applications?  What suggestions do you have for a maturing project that needs to grow out of a single folder or a single project?&lt;/p&gt;

&lt;p&gt;Did you know, I host a weekly live stream on the &lt;a href="https://twitch.tv/visualstudio" rel="noopener noreferrer"&gt;Visual Studio Twitch channel&lt;/a&gt; teaching the basics of C#? Tune in on Mondays at 9a ET / 1300 UTC for two hours of learning in a beginner-friendly Q+A format with demos and sample code you can download.&lt;/p&gt;

&lt;p&gt;Looking to get started learning C#? Checkout our &lt;a href="https://docs.microsoft.com/users/dotnet/collections/yz26f8y64n7k07?WT.mc_id=friends-0000-jefritz" rel="noopener noreferrer"&gt;free on-demand courses on Microsoft Learn&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>My Favorite C# Features - Part 3: Nullability</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Fri, 09 Apr 2021 19:57:37 +0000</pubDate>
      <link>https://dev.to/dotnet/my-favorite-c-features-part-3-nullability-2mcg</link>
      <guid>https://dev.to/dotnet/my-favorite-c-features-part-3-nullability-2mcg</guid>
      <description>&lt;p&gt;I'm a practical programmer.  I don't like to over-optimize my code, and I want to make it very readable for the next person who needs to work with something that I wrote.  Consequently, I sometimes leave alternate interpretations and access patterns into my code that might not always work as expected.  A great example of this is the ability to pass &lt;code&gt;null&lt;/code&gt; into C# methods and trigger a different behavior.  This can lead to errors in future code where you are now accessing something that inadvertently is a &lt;code&gt;null&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;In C# 8, the langauge designers introduced a feature called &lt;a href="https://docs.microsoft.com/dotnet/csharp/nullable-references?WT.mc_id=friends-0000-jefritz"&gt;&lt;strong&gt;Nullable Reference Types&lt;/strong&gt;&lt;/a&gt; that allows you to define which variables could be null and which variables should &lt;strong&gt;NEVER&lt;/strong&gt; be null.&lt;/p&gt;

&lt;p&gt;In this article, and as an effort to help make myself a better programmer, we're going to review the nullable Reference Types feature of C# and discuss why it is an important feature that we should start using by default in our applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why null?
&lt;/h2&gt;

&lt;p&gt;As an object oriented language, C# has always had the concept of &lt;code&gt;null&lt;/code&gt; in code.  null is the absence of an object, its synonymous with "nothing" and is an easy concept for folks to understand when you declare a variable.  However, this can (and most likely WILL) lead to the dreaded &lt;code&gt;NullReferenceException&lt;/code&gt;, an error that indicates a &lt;code&gt;null&lt;/code&gt; object was acted on unexpectedly.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;PRO TIP:&lt;/em&gt; Sometimes, you'll hear C# programming folks refer to a &lt;code&gt;NullReferenceException&lt;/code&gt; as an NRE.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;myConsoleLogger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myConsoleLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processed the data"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the sample above, the &lt;code&gt;myConsoleLogger&lt;/code&gt; object is declared and assigned its default value (which is null).  This would trigger a &lt;code&gt;NullReferenceException&lt;/code&gt; because &lt;code&gt;myConsoleLogger&lt;/code&gt; was never assigned an instance of an object.  This is a simple mistake, but it would be really nice if the compiler caught this before we even tried to run the code.  Consider a scenario like this array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;firstValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is going to throw a &lt;code&gt;NullReferenceException&lt;/code&gt; also, because the &lt;code&gt;values&lt;/code&gt; array is declared but never assigned values.  The &lt;code&gt;firstValue&lt;/code&gt; variable is initialized with a &lt;code&gt;null&lt;/code&gt; value on line 2 and the &lt;code&gt;ToLower()&lt;/code&gt; method is then attempting to operate on a &lt;code&gt;null&lt;/code&gt; object.  Once again, a simple error because the &lt;code&gt;values&lt;/code&gt; array is never assigned values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nullable Contexts and Compiler Warnings to the Rescue!
&lt;/h2&gt;

&lt;p&gt;Some folks fear the compiler.  There's a feeling that the compiler throwing errors or emitting warnings is an intimidating practice.  I see it the other way:  The compiler is my friend telling me when I made a mistake before I attempt to run my application.  In this case, I want the compiler to tell me when I might work with a &lt;code&gt;null&lt;/code&gt; object because the variables weren't initialized properly.  Let's get some help to ensure that our objects in our code are being used correctly.&lt;/p&gt;

&lt;p&gt;By default in C#, any reference type can be assigned the &lt;code&gt;null&lt;/code&gt; value.  With C# 8 and .NET Core 3.0 and later, we can define contexts in and around our projects where the compiler will perform nullability checks and raise warnings if we are potentially going to throw a &lt;code&gt;NullReferenceException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can enable nullable checking on a segment of code by wrapping it with a compiler pre-processor &lt;code&gt;#nullable&lt;/code&gt; with a setting the indicates how it should behave.  Let's add nullability checking to the &lt;code&gt;Hat&lt;/code&gt; class I introduced in the previous post in this series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#nullable enable
&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;AcquiredYear&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;#nullable restore
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two pre-processor commands present in this code:  &lt;code&gt;#nullable enable&lt;/code&gt; and &lt;code&gt;#nullable restore&lt;/code&gt;.  The &lt;code&gt;enable&lt;/code&gt; command tells the compiler to check for variables that could be inadvertently assigned null and raise a compiler warning if there are any.  Sure enough, in the &lt;code&gt;Hat&lt;/code&gt; class, the string properties &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;Theme&lt;/code&gt; need to be initialized according to these compiler warnings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting 
constructor. Consider declaring the property as nullable. 
warning CS8618: Non-nullable property 'Theme' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This are easy fixes as I can default the values for these two properties to &lt;code&gt;string.Empty&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="cp"&gt;#nullable enable
&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;AcquiredYear&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#nullable restore
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler warnings go away, and I am a happy developer.  If I try to define a &lt;code&gt;Hat&lt;/code&gt; and assign &lt;code&gt;null&lt;/code&gt; to these fields, will the compiler catch it?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newHat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Phillies 80's Maroon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;AcquiredYear&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1985&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code DOES compile with no warnings.  Why?  The &lt;code&gt;#nullable&lt;/code&gt; compiler directive is set on the &lt;code&gt;Hat&lt;/code&gt; class, not the construction of the &lt;code&gt;newHat&lt;/code&gt; variable.  In order to protect more of our code, we need to expand the nullable check's scope to include more of our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="cp"&gt;#nullable enable
&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newHat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Phillies 80's Maroon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;AcquiredYear&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1985&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#nullable restore
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This raises the appropriate compiler warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning CS8625: Cannot convert null literal to non-nullable reference type.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review quickly:  these are ONLY compiler warnings.  In fact, this code will run and not produce any errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declaring a Reference Type as Nullable
&lt;/h2&gt;

&lt;p&gt;I can also tell the compiler that it's ok if one of these reference values is assigned null by attaching a &lt;code&gt;?&lt;/code&gt; to the end of it's variable declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;AcquiredYear&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With this change, the &lt;code&gt;Name&lt;/code&gt; of the hat is allowed to be assigned &lt;code&gt;null&lt;/code&gt; regardless of the Nullable context around the class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project-wide Nullable Checking
&lt;/h2&gt;

&lt;p&gt;What if I want to roll-out this compiler interaction across my ENTIRE project.  You can add an entry to your project file that indicates nullable checking should be enabled with the &lt;code&gt;Nullable&lt;/code&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net5.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now remove the &lt;code&gt;#nullable&lt;/code&gt; directives from the &lt;code&gt;Hat&lt;/code&gt; class and I'll receive the same compiler warnings without writing more code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable Nullable Checking
&lt;/h2&gt;

&lt;p&gt;What if I have an application that is configured with the &lt;code&gt;Nullable&lt;/code&gt; entry in the project file, and I want to relax the checking on various sections of my application?&lt;/p&gt;

&lt;p&gt;Similar to before, we can add a processor directive to our code that disables null checking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="cp"&gt;#nullable disable
&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newHat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Phillies 80's Maroon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;AcquiredYear&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1985&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#nullable restore
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're talking...  I can enforce the better developer behavior by adding the Nullable check to my project file, and those developers that want to take the risk of assigning and working with &lt;code&gt;null&lt;/code&gt; can wrap their code with the processor to remove the warnings.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Step
&lt;/h2&gt;

&lt;p&gt;Warnings are just silly yellow text the compiler emits that tells us we MIGHT have a concern in our project.  Did you know that you can turn up the importance of this warnings, converting them to errors the compiler emits and ensuring that you write better code?  Add the &lt;code&gt;TreatWarningsAsErrors&lt;/code&gt; element to your project file and those pesky warnings become a real problem that blocks your project from compiling properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net5.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TreatWarningsAsErrors&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/TreatWarningsAsErrors&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our project team will be forced to treat &lt;code&gt;null&lt;/code&gt; values with more respect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The ability to assign and work with the &lt;code&gt;null&lt;/code&gt; value is valuable in C#, but can be misused and lead to errors in our running applications.  Let's get some help from the compiler to make handling of &lt;code&gt;null&lt;/code&gt; values easier and clearer when we're building our projects.&lt;/p&gt;

&lt;p&gt;Did you know, I host a weekly live stream on the &lt;a href="https://twitch.tv/visualstudio"&gt;Visual Studio Twitch channel&lt;/a&gt; teaching the basics of C#? Tune in on Mondays at 9a ET / 1300 UTC for two hours of learning in a beginner-friendly Q+A format with demos and sample code you can download.&lt;/p&gt;

&lt;p&gt;Looking to get started learning C#? Checkout our &lt;a href="https://docs.microsoft.com/users/dotnet/collections/yz26f8y64n7k07?WT.mc_id=friends-0000-jefritz"&gt;free on-demand courses on Microsoft Learn!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>My Favorite C# Features Part 2: LINQ</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Wed, 10 Mar 2021 15:04:16 +0000</pubDate>
      <link>https://dev.to/dotnet/my-favorite-c-features-part-2-linq-57kd</link>
      <guid>https://dev.to/dotnet/my-favorite-c-features-part-2-linq-57kd</guid>
      <description>&lt;p&gt;Working with collections in any programming language always ends up with some sort of loop structure and ugly code to find an object, work on several objects, and exit the loop.  This is why I really enjoy using LINQ with C# -- all of this looping and aggregation code is hidden from me by the compiler and I can focus on writing the code that I actually need to get and work with data in a collection.  In this post, I'll review some of my favorite LINQ features that make me more productive in working with collections of data.&lt;/p&gt;

&lt;p&gt;Throughout the samples below, we'll work with this collection of Hat objects.  It's a real collection, and yes I do have these hats IRL.  You can see a large selection of my hat collection at &lt;a href="https://hats.csharpfritz.com"&gt;https://hats.csharpfritz.com&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// A name I've assigned to the hat&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// The year I acquired the hat&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Theme of the hat: Sports, Movies, Tech, etc&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HatCollection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Camp Crystal Lake"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Movies"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Marauder's Map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Movies"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Super C#"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Tech"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Dunder Mifflin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"TV"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Space X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2019&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Tech"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Phillies 2008 World Series"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Sports"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Hat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"The Flash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"TV"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnwkgh7p5bph0ssd9cqf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnwkgh7p5bph0ssd9cqf.jpg" alt="Fritz's The Flash hat" width="400" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
Fritz's The Flash hat



&lt;h2&gt;
  
  
  Where - Find Some Data and Return It
&lt;/h2&gt;

&lt;p&gt;What good is a collection of data if you can't search through it quickly with just a 1 line command?  The &lt;code&gt;Where&lt;/code&gt; method can be used to quickly find the subset of items that meet your condition.  &lt;/p&gt;

&lt;p&gt;Given the collection of hats, we could return just those hats that were acquired in 2020 with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;twentyTwentyHats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;==&lt;/span&gt;&lt;span class="m"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Returns "Camp Crystal Lake" and "Marauder's Map" hat objects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of the &lt;code&gt;Where&lt;/code&gt; method are called a lambda expression.  You define a lambda with a variable that will capture one of the items in the collection, add a 'fat arrow' and then the operation you want to process on that item.  In the case of a &lt;code&gt;Where&lt;/code&gt; method, we are testing for a condition and returning a true or false boolean value to indicate if the item should be returned.  &lt;/p&gt;

&lt;p&gt;In this case, we are testing if the &lt;code&gt;Year&lt;/code&gt; property of the &lt;code&gt;Hat&lt;/code&gt; is 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are ANY of these Hats from before 2010?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Any&lt;/code&gt; method is a simple check to return a true or false boolean value indicating if a condition is met.  If we want to search the collection for hats that are from before 2010, we could use this expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;olderThanTwentyTen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Returns true due to the presence of the 2008 Phillies hat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Any&lt;/code&gt; method can operate quickly as it will stop looping through the collection as soon as the condition is met.&lt;/p&gt;

&lt;h2&gt;
  
  
  Count those hats
&lt;/h2&gt;

&lt;p&gt;Aggregate methods are available that allow you to count, sum, min, max, and average values inside the collection.  In addition to simply counting all of the items in the collection, we can provide a test method to count only those items that pass that test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;totalHats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This returns 7.. but honestly, &lt;/span&gt;
&lt;span class="c1"&gt;// Fritz's hat collection is more than 100&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;techHatsCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Tech"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This will return 2 for "Super C#" and "Space X"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sorting done simply
&lt;/h2&gt;

&lt;p&gt;Sorting is one of those computer science gotcha questions that ALWAYS comes up in an interview and nobody likes it.  When it comes to sorting collections in memory, I just let the experts who built .NET do it for me by using the &lt;code&gt;OrderBy&lt;/code&gt; and &lt;code&gt;OrderByDescending&lt;/code&gt; methods.  Simply provide a selector method that returns the property or value to order by and LINQ will return to you a collection of your objects in the order desired:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newestHatsFirst&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orderByTheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you know, you can chain these sort method together, or even connect them with a &lt;code&gt;Where&lt;/code&gt; method to create a more interesting query?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;techHatsNewestFirst&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Tech"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This returns the "Space X", "Super C#" hat objects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project your output with Select
&lt;/h2&gt;

&lt;p&gt;Just like in SQL, there is a &lt;code&gt;Select&lt;/code&gt; method that can be used with LINQ to transform our collection from one object to another.  Perhaps we just want an array of the hat names... easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hatNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use select to convert to another type, an anonymous type, or tuples.  Use &lt;code&gt;Select&lt;/code&gt; to give you the shape and format of the data you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Group By FTW!
&lt;/h2&gt;

&lt;p&gt;It's nice to be able to sort and filter your data, but the real power comes in when you summarize a collection.  Let's use the &lt;code&gt;GroupBy&lt;/code&gt; feature to summarize the number of hats in the collection by theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;totalByTheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HatCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GroupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;totalByTheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Theme: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Count: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* 
Outputs:

Theme: Movies, Count: 2
Theme: Tech, Count: 2
Theme: TV, Count: 2
Theme: Sports, Count: 1

*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;GroupBy&lt;/code&gt; delivers a collection of grouped objects with a &lt;code&gt;Key&lt;/code&gt; property that contains the value grouped by, in this case the &lt;code&gt;Theme&lt;/code&gt; property.  We can then chain the &lt;code&gt;Select&lt;/code&gt; method to project these groupings into a summary collection with the themes and the count of hats that belong to each theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This is just the beginnings of the cool things you can do with LINQ. Put together with an object-relational mapper tool like Entity Framework and you have a very cool way to query your database.&lt;/p&gt;

&lt;p&gt;Did you know, I host a weekly live stream on the &lt;a href="https://twitch.tv/visualstudio"&gt;Visual Studio Twitch channel&lt;/a&gt; teaching the basics of C#?  Tune in on Mondays at 9a ET / 1400 UTC for two hours of learning in a beginner-friendly Q+A format with demos and sample code you can download.  I recently had an episode about LINQ that you can find on YouTube:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/knc4AVqHEr0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Looking to get started learning C#? Checkout our &lt;a href="https://docs.microsoft.com/users/dotnet/collections/yz26f8y64n7k07?WT.mc_id=friends-0000-jefritz"&gt;free on-demand courses on Microsoft Learn!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>My Favorite C# Features - Part 1: Strong-types, Implicit-types, Anonymous-types, and Target-types</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Fri, 19 Feb 2021 16:10:15 +0000</pubDate>
      <link>https://dev.to/dotnet/my-favorite-c-features-part-1-strong-types-implicit-types-anonymous-types-and-target-types-12a5</link>
      <guid>https://dev.to/dotnet/my-favorite-c-features-part-1-strong-types-implicit-types-anonymous-types-and-target-types-12a5</guid>
      <description>&lt;p&gt;I've been a long-time developer and fan of the C# programming language. Heck, I even named &lt;a href="https://csharpfritz.com"&gt;my blog&lt;/a&gt; and took the nickname &lt;a href="https://twitch.tv/csharpfritz"&gt;csharpfritz&lt;/a&gt;  One of my favorite capabilities of the language is the immediate compiler checking and tooling support for type-checking.  The instant check can save time and prevent a number of bugs in writing code quickly.  With the latest updates in C# 9 and .NET 5, we now have ultimate flexibility in how types are declared and interacted with in our code.  Let's review the easy ways to declare and initialize types with C#.&lt;/p&gt;

&lt;h2&gt;
  
  
  In the beginning, there was explicit-typing
&lt;/h2&gt;

&lt;p&gt;The original versions of C# required explicit declaration of every type in your code, and it felt so redundant to type the same names over and over again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sandwich&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Toppings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bacon"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Toppings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lettuce"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Toppings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tomato"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gluten-Free"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sandwich&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// prep your sandwich as you'd prefer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether you are declaring the variable or initializing it with a class, you must explicitly declare the type assigned to the variable.  Both &lt;code&gt;myBLT&lt;/code&gt; and &lt;code&gt;yourSandwich&lt;/code&gt; were required to have the type declaration &lt;code&gt;Sandwich&lt;/code&gt; preceding them.&lt;/p&gt;

&lt;p&gt;This syntax has been valid since C# v1 and is still valid today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Implicit-Typing and Initializers
&lt;/h2&gt;

&lt;p&gt;The language was simplified a bit with C# 3 in 2007 when the &lt;a href="https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/var?WT.mc_id=friends-0000-jefritz"&gt;&lt;code&gt;var&lt;/code&gt; keyword and implicit typing&lt;/a&gt; was introduced.  The compiler would use this keyword to infer variable types when they were initialized.  The C# team also introduced initializers in C# 3, a feature that would allow you to assign properties at declaration time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Toppings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Bacon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lettuce"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tomato"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;Bread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gluten-Free"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sandwich&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// prep your sandwich as you'd prefer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;var&lt;/code&gt; keyword delivers no performance hit to your running code, nor does it add to compile time.  It is strictly a bit of 'syntactic sugar' that makes it easier to initialize and declare variables.  I've demonstrated an initializer in the above sample by setting the &lt;code&gt;Bread&lt;/code&gt; value to "Gluten-Free" and I've introduced another feature that arrived with C# 3: an implictly-typed array of strings assigned to the &lt;code&gt;Toppings&lt;/code&gt; property of &lt;code&gt;mySandwich&lt;/code&gt;.  The compiler determines that the array is an array of strings and assigns the type appropriately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types aren't for me - Anonymous Types
&lt;/h2&gt;

&lt;p&gt;At the same time Implicit-Typing was introduced, the &lt;a href="https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types"&gt;anonymous type&lt;/a&gt; was added to C#.  With this feature, you can declare a type with a set of read-only properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Toppings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Bacon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lettuce"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tomato"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;Bread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gluten-Free"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sandwich&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// prep your sandwich as you'd prefer&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ourLunchOrder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;YourItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now inspect the &lt;code&gt;outLunchOrder&lt;/code&gt; variable and read the properties.  While anonymous types are convenient for prototyping, they shouldn't be used across namespace or memory boundaries, preferring instead to deliver a clear API to your interacting methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Welcome to 2021 - Target-Types
&lt;/h2&gt;

&lt;p&gt;Implicit-typing forced the definition of types to the right of the equals sign when initializing a variable.  Perhaps you'd prefer to keep the types on the left of the equals sign, so that all types are in the same location in your code.  With C# 9 and .NET 5, this feature is now available to you and it's called &lt;a href="https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-9#fit-and-finish-features"&gt;Target-Typing&lt;/a&gt;.  Let's rewrite our lunch order using this syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Toppings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Bacon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lettuce"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tomato"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;Bread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gluten-Free"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Sandwich&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sandwich&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// prep your sandwich as you'd prefer&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ourLunchOrder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myBLT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;YourItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yourSandwich&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, when calling methods and passing in new objects you can use the &lt;code&gt;new()&lt;/code&gt; keyword to create an object of the expected type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;IceCreamSundae&lt;/span&gt; &lt;span class="n"&gt;myDessert&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;myDessert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Toppings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Flavor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Chocolate"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The C# programming language is so flexible and allows you to take advantage of the multitude of resources in the .NET frameworks easily and in the way you want.  With a smart compiler that provides access to alternate syntax that gives you the freedom to write code so that it is readable for you, I'm happier than ever to be using C#.&lt;/p&gt;

&lt;p&gt;Over the next few weeks, I'm going to write additional entries in this series about my favorite features of C#.  What do you like about the language?  What do you want to see some discussion and samples of?  I'll be back next week with more C# features to discuss.&lt;/p&gt;

&lt;p&gt;Looking to get started learning C#? Checkout our &lt;a href="https://docs.microsoft.com/users/dotnet/collections/yz26f8y64n7k07?WT.mc_id=friends-0000-jefritz"&gt;free on-demand courses on Microsoft Learn&lt;/a&gt;!  Every Monday, check out my C# with CSharpFritz live-video training series &lt;a href="https://twitch.tv/visualstudio"&gt;on Twitch&lt;/a&gt; and &lt;a href="https://www.youtube.com/playlist?list=PLdo4fOcmZ0oXv32dOd36UydQYLejKR61R"&gt;archived on YouTube&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Top 7 OBS Studio Tricks for 2020 – and you won’t believe #4</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Thu, 23 Jul 2020 13:38:44 +0000</pubDate>
      <link>https://dev.to/csharpfritz/top-7-obs-studio-tricks-for-2020-and-you-won-t-believe-4-ag4</link>
      <guid>https://dev.to/csharpfritz/top-7-obs-studio-tricks-for-2020-and-you-won-t-believe-4-ag4</guid>
      <description>&lt;p&gt;I’m writing this blog post live on stream on July 23, 2020 with about 100 folks watching over my shoulder. We’re discussing some of the techniques that I use to assemble and broadcast my regular Twitch stream, and I wanted to share some of those links and features with you.&lt;/p&gt;

&lt;p&gt;Let’s start with OBS plugins and tricks that I use.&lt;/p&gt;

&lt;p&gt;I broadcast and produce video using OBS Studio, a free and open-source project. They have a &lt;a href="https://patreon.com/OBSProject"&gt;patreon&lt;/a&gt; available to support the development of this valuable tool that so many streamers use. I encourage you to support their project with a donation.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Closed Captioning in the Cloud
&lt;/h2&gt;

&lt;p&gt;Everyone who tunes in to your stream should be able to participate, especially those folks who might not be able to hear you or people who don’t primarily speak your language. There are a number of different plugins and extensions that will provide closed captioning for you, but they have accessibility issues EXCEPT for the Twitch video player closed captioning.&lt;/p&gt;

&lt;p&gt;Twitch’s video player has a keyboard accessible closed-captioning button and it also allows the viewers to change font and color. Importantly, screen readers can access this content AND the captions persist in the video archive.&lt;/p&gt;

&lt;p&gt;I recommend using the &lt;a href="https://github.com/ratwithacompiler/OBS-captions-plugin"&gt;Cloud Closed Captions plugin&lt;/a&gt; from ‘ratwithacompiler’ and available on GitHub. Once added to OBS, you can easily configure an audio source to monitor and create captions from. This allows you to isolate just your microphone from any music so that JUST your voice is transcribed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WM5C0s7P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/CloudCaptionsScreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WM5C0s7P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/CloudCaptionsScreenshot.png" alt="" width="682" height="808"&gt;&lt;/a&gt;Configuration of the Cloud Closed Caption plugin in OBS Studio&lt;/p&gt;

&lt;h2&gt;
  
  
  2. NewTek NDI Plugin
&lt;/h2&gt;

&lt;p&gt;I connect OBS Studio to output video to Skype, Microsoft Teams, and other communication software as well as to bring video in from other video sources on my local network. NewTek makes their NDI video streaming technology available for free and you can connect it OBS with the &lt;a href="https://obsproject.com/forum/resources/obs-ndi-newtek-ndi%E2%84%A2-integration-into-obs-studio.528/"&gt;OBS-NDI plugin&lt;/a&gt; and run the &lt;a href="https://ndi.tv/tools/"&gt;NDI Tools&lt;/a&gt; to begin piping video into and out of your favorite communication applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WN_sqd1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WN_sqd1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image.png" alt="" width="471" height="240"&gt;&lt;/a&gt;NDI Output Settings from OBS Studio&lt;/p&gt;

&lt;p&gt;Installation of the OBS-NDI Plugin allows you to both export video as a streaming video source, and also consume a NDI streaming video as a source in your production. This screenshot above allows you to configure your output from OBS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vKvb7hl_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vKvb7hl_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-1.png" alt="" width="213" height="255"&gt;&lt;/a&gt;The ‘Add Source’ dialog with NDI Source now available&lt;/p&gt;

&lt;p&gt;When you add an NDI Source to a scene, you can choose the streaming source and configure it in a screen like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G5tHhM0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G5tHhM0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-2.png" alt="" width="714" height="577"&gt;&lt;/a&gt;Configuring an NDI Video Source for a scene in OBS&lt;/p&gt;

&lt;p&gt;The ‘Source Name’ is the name of the NDI streaming video that you want to capture. Bandwidth and Sync effect the connection speed and delay in your video. I highly recommend pushing this to ‘Highest Bandwidth’ and ‘Source Timing’ for real-time video interactions.&lt;/p&gt;

&lt;p&gt;Finally, when you embed one of these NDI sources in OBS, you &lt;em&gt;must&lt;/em&gt; use the ‘fit to frame’ and Scale to Inner Bounds features to ensure any reduction in bandwidth does not skew the size of your video. Right-click on the video-source, choose Transform – Edit Transform and set the ‘Bounding Box Type’ to ‘Scale to inner bounds’. You can also use the Ctrl+F hotkey to force this behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eDjS5PTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eDjS5PTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-3.png" alt="" width="561" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Custom Transitions
&lt;/h2&gt;

&lt;p&gt;I recently re-themed my stream with new backgrounds and a cool custom transition (or stinger as folks in the TV biz call it). My friend &lt;a href="https://jayniusgamingtv.wixsite.com/website"&gt;Jaynius Gaming&lt;/a&gt; put together these assets and I am now able to configure a webm movie file to display as my transition between scenes.&lt;/p&gt;

&lt;p&gt;You can add a video file to be used as a transition by clicking the + underneath the ‘Scene Transitions’ header in OBS Studio and configuring in this screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YQN3iLwa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YQN3iLwa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-8.png" alt="" width="722" height="428"&gt;&lt;/a&gt;Custom Transition Configuration screen&lt;/p&gt;

&lt;p&gt;I have added my transition animation and specified the exact frame when the screen is completely covered to change from one scene to the next. For my transition, which doesn’t have any audio, I do not want any audio changes or fading between scenes. I can click the ‘Preview Transition’ button to test the animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qMXeJgWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/TransitionDemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qMXeJgWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/TransitionDemo.gif" alt="" width="483" height="271"&gt;&lt;/a&gt;My new custom transition in OBS&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Move Transitions
&lt;/h2&gt;

&lt;p&gt;Fade and cut transitions in OBS Studio are simple but not too elegant. I’ve learned how to make my scene transitions look a little more fluid by using the &lt;a href="https://obsproject.com/forum/resources/move-transition.913/"&gt;Move Transition plugin&lt;/a&gt;. With this plugin, any matching video sources from one scene to the next will gracefully move to their new locations when changing scenes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SeKg8WJp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SeKg8WJp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-6.png" alt="" width="718" height="988"&gt;&lt;/a&gt;Configuration of the Move transition&lt;/p&gt;

&lt;p&gt;There are a bunch of options here, but I use it with the default configuration to allow my content to move around the screen as I change scenes. You’ll see this when I transition between the various full-screen background scenes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AqH5b-T1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/MotionDemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AqH5b-T1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/MotionDemo.gif" alt="" width="" height=""&gt;&lt;/a&gt;Sample of the Move transition at work on my stream&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Multiple Actions in StreamDeck
&lt;/h2&gt;

&lt;p&gt;The next technique is a trick to make several animations appear as one fluid transition without having to press a bunch of buttons and manually trigger interactions with OBS Studio. The StreamDeck software has the ability to trigger multiple actions from one button press. Here is the set of actions that I trigger for the animated GIF above:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g4xcrcG5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g4xcrcG5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-7.png" alt="" width="513" height="561"&gt;&lt;/a&gt;The Multiple Actions configuration in StreamDeck&lt;/p&gt;

&lt;p&gt;Under the ‘StreamDeck’ actions section you can choose ‘Multi Action’ and configure one button to trigger multiple OBS Scenes. In the above Multi Action, I hide the sources that I don’t want to appear and start activating with a timer each of the scenes the compose the overall animation. The timer is set to the duration of each animation segment.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Transition Override Matrix Plugin
&lt;/h2&gt;

&lt;p&gt;With all of these new techniques to animate and transition between scenes in OBS Studio, we will want a little more control over how each transition animation activates between scenes. The &lt;a href="https://obsproject.com/forum/resources/obs-transition-matrix.751/"&gt;Transition Override Matrix plugin&lt;/a&gt;allows you to specify the exact animation to be used from one specific scene to another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9k4JrotI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9k4JrotI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-9.png" alt="" width="800" height="586"&gt;&lt;/a&gt;The transitions for my stream to effect the various animation and my custom stinger&lt;/p&gt;

&lt;p&gt;The scenes listed down the left side, in the rows are the source scenes or where you will be transitioning FROM and the columns are the scenes that you will be transitioning to. Right-click on a box to set a specific transition to show when changing between those two scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Featured.Chat
&lt;/h2&gt;

&lt;p&gt;The chat room on Twitch is a phenomenal resource and when we’re in Ask Me Anything mode, I want to be able to highlight the current question and answer it clearly on video. Featured.Chat allows me to review the chatroom content and queue up messages to appear nicely on screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G2bhAJ_r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G2bhAJ_r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-4.png" alt="" width="510" height="124"&gt;&lt;/a&gt;Featured.Chat message on screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://featured.chat"&gt;Featured.Chat&lt;/a&gt; is maintained by Slevinth Heaven, and is embedded in OBS as a browser source. I can select messages and put them live on screen using their chat console in another browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_U8Ir5Q---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-5-1024x529.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_U8Ir5Q---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/07/image-5-1024x529.png" alt="" width="800" height="413"&gt;&lt;/a&gt;The Featured.Chat Administration console&lt;/p&gt;

&lt;p&gt;I have mine configured with a notification bell so that if a moderator puts a message live on screen, I will hear and recognize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;These are techniques that I’ve used in 2020 to make my video production look unique and appear more professional for my viewers. There are tons of OBS Plugins that you can download and try out for recordings or live streams. What are some of your favorite tips for getting more out of OBS Studio? Let me know in the comments below.&lt;/p&gt;

</description>
      <category>tips</category>
      <category>technology</category>
      <category>livestream</category>
      <category>obs</category>
    </item>
    <item>
      <title>Minimal March – Part 2 : .NET on a Chromebook</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Wed, 04 Mar 2020 14:32:23 +0000</pubDate>
      <link>https://dev.to/dotnet/minimal-march-part-2-net-on-a-chromebook-pio</link>
      <guid>https://dev.to/dotnet/minimal-march-part-2-net-on-a-chromebook-pio</guid>
      <description>&lt;p&gt;After writing my previous post in this &lt;a href="https://jeffreyfritz.com/tag/minimalmarch/"&gt;Minimal March&lt;/a&gt; series, it was pointed out to me that my approach is still a little bit of ‘&lt;a href="https://www.urbandictionary.com/define.php?term=Gatekeeping"&gt;gatekeeping&lt;/a&gt;‘. I was using a very expensive machine with lots of memory and drive space in a virtual machine. What about those folks that don’t have access to these resources? Let’s knock down those doors and show that ANYONE ANYWHERE can be a .NET developer.&lt;/p&gt;

&lt;p&gt;I set the following parameters for myself, to ensure that I was getting a computer that just about anyone could acquire:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Purchase a laptop at my local discount retail shop, a Walmart in my case.&lt;/li&gt;
&lt;li&gt;Spend less than $200&lt;/li&gt;
&lt;li&gt;It must be a Chromebook – this is now very common in high-schools here in the US&lt;/li&gt;
&lt;li&gt;Configure it with .NET developer tools and work on productive software on my Twitch stream&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;… and it worked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/videos/561287709?tt_content=text_link&amp;amp;tt_medium=vod_embed"&gt;Watch Minimal March PIVOT! Live Coding .NET on a Chromebook !coffee from csharpfritz on www.twitch.tv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Urban Dictionary defines Gatekeeping as the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When someone takes it upon themselves to decide who does or does not have access or rights to a community or identity.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href="https://www.urbandictionary.com/define.php?term=Gatekeeping&amp;amp;defid=6476252"&gt;Urban dictionary&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve seen this in our technical and software development communities on Twitter, Reddit, in-person, and even at conferences. Teens and college graduates are again and again told that they can’t be considered a ‘real developer’ unless they use &lt;strong&gt;technology X&lt;/strong&gt; where X is the “cool” or “hip” tools to use this month. How many developers do you see in the San Francisco area that DON’T carry Mac laptops? At Microsoft technology events, how many presenters are carrying a Surface Book?&lt;/p&gt;

&lt;p&gt;For a developer presentation at an event, it is GOOD to have a fast, brand-name machine so that your demos work quickly and you can get access to spare parts easily should something go wrong. If you’re someone interested in getting started in software, there is &lt;em&gt;NO NEED&lt;/em&gt; to spend $3,000 on that fully-loaded Mac Book, Alienware, or Surface Book. Let’s get started with something simple, something you can access without taking out a loan.&lt;/p&gt;

&lt;p&gt;Yes, we could build a machine around a Raspberry Pi. That would require some technical knowledge, acquiring a display, adding a keyboard and mouse and not being at all practical for students or developers to carry with them to school, the local coffee shop, or the office.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Walmart Challenge
&lt;/h2&gt;

&lt;p&gt;Walmart has a great cross-section of technology at their retail stores. You can find iPhones, Playstation 4, XBox, laptops and other expensive systems right next to very inexpensive Android phones, tablets, and Chromebooks. Every town in North America has at least one Walmart, and I visited my local store on Monday evening this week in search of a bargain.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1234634393429381123-498" src="https://platform.twitter.com/embed/Tweet.html?id=1234634393429381123"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1234634393429381123-498');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1234634393429381123&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I did a quick walk through the computer section and looked at the candidates. Here is what I found:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-CQTVSTGEbo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Shopping for $200 Chromebooks at Walmart



&lt;p&gt;… and I settled on this &lt;a href="https://www.walmart.com/ip/HP-Chromebook-14-14-Full-HD-Display-AMD-A4-9120C-AMD-Radeon-R4-Graphics-4-GB-SDRM-32GB-eMMC-Audio-by-B-O-Ink-Blue-14-db0043wm/309927001"&gt;HP Chromebook 14&lt;/a&gt;, saving $50 off the list price and coming in JUST under my $200 budget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FclVMIMy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/image-2-1024x413.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FclVMIMy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/image-2-1024x413.png" alt="" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4GB of RAM and 32GB of drive space with an AMD A4. This would be a tight fit, but we should be able to write code and build web applications on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Linux
&lt;/h2&gt;

&lt;p&gt;“Installing” is probably the wrong term and “Activating” is the better term now. With the latest versions of ChromeOS, Google now has &lt;a href="https://support.google.com/chromebook/answer/9145439?hl=en"&gt;instructions for installing Linux&lt;/a&gt; on your Chromebook available. I couldn’t believe that it would be THIS easy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clips.twitch.tv/embed?clip=GeniusPopularLarkPicoMause"&gt;Installing Linux on a ChromeBook - It's THAT easy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a few minutes, I had a terminal running that had ALL of the Linux features I wanted. I couldn’t believe it was that easy… but there are some limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That Linux instance is running inside of a container&lt;/li&gt;
&lt;li&gt;It’s named ‘penguin’ and as much as you might want to rename it, that penguin name is going to come back&lt;/li&gt;
&lt;li&gt;Interactions with the Chrome UI aren’t easy&lt;/li&gt;
&lt;li&gt;Forget about fonts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those last two items were a little hard for me. I have a set of fonts that I like to use while developing, and I fought the good fight.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fonts, Developer Mode and Bricks
&lt;/h2&gt;

&lt;p&gt;There currently is no way to install fonts on ChromeOS through the native menu and user-interface.  After some searching online, I found some instructions about rebuilding the hard drive in 'developer mode'.  The steps for this are not hard to follow, but require you to change the drive partition that ChromeOS boots from.  Furthermore, developer-mode requires you to use a Ctrl+d keystroke to activate the machine at boot time.  When you configure developer-mode you will be presented this screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qr0DCTPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://external-content.duckduckgo.com/iu/%3Fu%3Dhttps%253A%252F%252Fi1.wp.com%252Fbeebom.com%252Fwp-content%252Fuploads%252F2016%252F06%252FChrome-OS-preparing-system-for-developer-mode.jpg%253Fresize%253D640%25252C308%26f%3D1%26nofb%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qr0DCTPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://external-content.duckduckgo.com/iu/%3Fu%3Dhttps%253A%252F%252Fi1.wp.com%252Fbeebom.com%252Fwp-content%252Fuploads%252F2016%252F06%252FChrome-OS-preparing-system-for-developer-mode.jpg%253Fresize%253D640%25252C308%26f%3D1%26nofb%3D1" alt="How to Enable Developer Mode on Chrome OS to Get Root Access" width="640" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Developer Mode activated, you can read and write to the entire disk. Brilliant! I can copy my fonts into an appropriate folder and activate them. After placing them in the /usr/local/share/fonts folder and fighting with font utilities for about an hour, I shut down the machine and went to dinner.&lt;/p&gt;

&lt;p&gt;When I returned, I accidentally pressed the &lt;code&gt;spacebar&lt;/code&gt;INSTEAD of&lt;code&gt;Ctrl+d&lt;/code&gt; to activate my Chromebook… and this happened:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6jHNHHBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/20200304_034642762_iOS-1024x576.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6jHNHHBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/20200304_034642762_iOS-1024x576.jpg" alt="" width="800" height="450"&gt;&lt;/a&gt;Uh oh…&lt;/p&gt;

&lt;p&gt;Fortunately, there is a very well documented &lt;a href="https://support.google.com/chromebook/answer/1080595?hl=en"&gt;system restore process for ChromeOS&lt;/a&gt;. After restoring the OS, I decided to abandon Developer Mode going forward.&lt;/p&gt;
&lt;h2&gt;
  
  
  FiraCode in the ChromeOS Terminal
&lt;/h2&gt;

&lt;p&gt;The ChromeOS terminal is actually more akin to a web page that you can format with CSS. It’s not, in my exploration, able to see into the files and folders on your Linux container running in the terminal. However, you can configure it with some custom CSS to use fonts that are available on the web.&lt;/p&gt;

&lt;p&gt;The folks working on the &lt;a href="https://github.com/tonsky/FiraCode/wiki/ChromeOS-Terminal"&gt;FiraCode font made directions available&lt;/a&gt; to add their font as a font-family and CSS markup to enable it in the terminal. It’s not perfect, but now my eyes are more at rest with the font-ligatures and fixed-width text for coding.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding my Linux Configuration
&lt;/h2&gt;

&lt;p&gt;I took my previous configuration from my last blog post and stashed it on my GitHub as a repository called &lt;a href="https://github.com/csharpfritz/dotfiles"&gt;dotfiles&lt;/a&gt; that I could download to any machine with a git client. I added my current .bashrc, .vimrc, and wallpapers to the repository and copied the git commands from &lt;a href="https://jeffreyfritz.com/2020/03/minimal-march-part-1-getting-started-with-net-and-c-at-the-command-line/"&gt;my previous blog post&lt;/a&gt; into a series of scripts to help me fetch and configure the plugins for vim.&lt;/p&gt;

&lt;p&gt;Once the repository was cloned locally, I ran the scripts in the /bin folder and I had Omnisharp, EditorConfig, and the NERDTree plugins installed along with my fonts downloaded, and the git features for my prompt configured.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing the .NET SDK
&lt;/h2&gt;

&lt;p&gt;The .NET SDK was just as easy to install as it was in my previous blog post, and the same instructions from my installation in a Linux VM worked again. This time, instead of getting a 64-bit version of the SDK, I got an AMD 64-bit optimized version. I can write the same code, target the same .NET Core libraries, and the appropriate runtime for my Chromebook would execute the code for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Performance, well this is where things start to slow down. This machine has a dual-core processor running at 1.8 GHz. Compiling and running my &lt;a href="https://github.com/fritzandfriends/BlazorWebFormsComponents"&gt;Blazor project and unit tests&lt;/a&gt; took a very long 20-30 seconds instead of the snappy 3 seconds that I was used to in the Linux VM.&lt;/p&gt;

&lt;p&gt;It WORKED, and that’s the important part, but I think we can do better. I’m going to work on optimizing some build scripts to make this run quicker going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I’m going to continue to work with this Chromebook for the rest of this week and probably next week as well. Let’s see how much performance we can squeeze out of this little machine and maybe even generate some scripts to help other developers who are working with similar machines and configurations.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>chromebook</category>
      <category>linux</category>
    </item>
    <item>
      <title>Minimal March – Part 1: Getting Started with .NET and C# at the Command-line</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Mon, 02 Mar 2020 15:56:55 +0000</pubDate>
      <link>https://dev.to/dotnet/minimal-march-part-1-getting-started-with-net-and-c-at-the-command-line-76k</link>
      <guid>https://dev.to/dotnet/minimal-march-part-1-getting-started-with-net-and-c-at-the-command-line-76k</guid>
      <description>&lt;p&gt;I wrote this tweet roughly a week ago about the state of .NET development that I was seeing on Twitter:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1231216659077181440-601" src="https://platform.twitter.com/embed/Tweet.html?id=1231216659077181440"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1231216659077181440-601');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1231216659077181440&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I see ‘Minimal March’ as a developer challenge for me, I’m someone who has spent the majority of the last 15 years working in a version of Visual Studio and C#. Let’s take away those comfortable and productive tools and expose me to more operating systems and more ways that folks can write applications. In this post, I’m going to outline the parameters of this .NET development event and show my initial configuration on Linux. I built this configuration live on Twitch stream on March 1, 2020.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/videos/560280479?tt_content=text_link&amp;amp;tt_medium=vod_embed"&gt;Watch Minimal March begins! .NET and Blazor development with text editors and command-line tools. !coffee from csharpfritz on www.twitch.tv&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Parameters
&lt;/h2&gt;

&lt;p&gt;This event is all about using the smallest, least expensive, and most customizable tools to build .NET applications that are NOT provided by Microsoft. To that end, I’m starting with the following configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ubuntu.com/download/desktop"&gt;Ubuntu Linux 18.04 LTS&lt;/a&gt; running in a VM&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet-core/3.1"&gt;.NET SDK 3.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vim.org/"&gt;vim 8.x&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration provides minimal ‘big productivity’ features out of the box, but allows us to build console and server applications easily with just a terminal window and a browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jeffreyfritz.com/wp-content/uploads/2020/03/image.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ByfwSJJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/image.png" alt="" width="800" height="450"&gt;&lt;/a&gt;Snapshot of my configuration at the conclusion of this article&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation Steps
&lt;/h2&gt;

&lt;p&gt;I followed &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/install/linux-package-manager-ubuntu-1804"&gt;the instructions on the .NET website to install the .NET SDK v3.1.2 and command-line tools using a package manager&lt;/a&gt; on my fresh Linux VM. After adding the required Microsoft repository configuration from those linked directions, I was able to run the following command to install .NET:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install dotnet-sdk-3.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I love seeing a very Linux-friendly way to work with .NET, right from the start.&lt;/p&gt;

&lt;p&gt;Next, I wanted to enable syntax highlighting and type-ahead for my *.cs source code in vim. Fortunately, there is the community-owned &lt;a href="https://omnisharp.net"&gt;Omnisharp project&lt;/a&gt; that provides support for vim. BUT… its not as simple as an apt-get command to install.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing vim
&lt;/h3&gt;

&lt;p&gt;vim (not vi, I made that mistake) is EXTREMELY versatile and can do many things, including running plugins when a plugin-manager is installed. For my configuration, I was able to use the built-in package manager for vim and just clone some files into my local directory to activate these plugins. First up was adding the &lt;a href="https://github.com/OmniSharp/Omnisharp-vim"&gt;Omnisharp&lt;/a&gt; plugin with a simple command to fetch from GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git://github.com/OmniSharp/omnisharp-vim ~/.vim/pack/plugins/start/omnisharp-vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I wanted a file-browser in vim. For this, I was recommended to try out &lt;a href="https://github.com/preservim/nerdtree"&gt;NERDTree&lt;/a&gt; and installed that with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/preservim/nerdtree.git ~/.vim/pack/vendor/start/nerdtree
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I wanted to add the ability to enforce my &lt;a href="https://editorconfig.org/"&gt;EditorConfig settings&lt;/a&gt; using the &lt;code&gt;.editorconfig&lt;/code&gt; configuration from the project folder. Fortunately, there’s an &lt;a href="https://github.com/editorconfig/editorconfig-vim"&gt;editorconfig plugin&lt;/a&gt; to handle this too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/editorconfig/editorconfig-vim.git ~/.vim/pack/local/start/editorconfig-vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created my first &lt;code&gt;.vimrc&lt;/code&gt; file with the following entries to make it a little easier to get around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set nocompatible
filetype indent plugin on

map &amp;lt;C-n&amp;gt; :NERDTreeToggle&amp;lt;CR&amp;gt;
set number " show line-numbers
set tabstop=2 " tab width is 2 spaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can now use Ctrl+n to open and close my “file-explorer”, the NERDTree. I’ve also turned on line numbers and set my tab-width to my preferred two spaces so that I can fit more code on screen during screencasting.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-screen keystrokes
&lt;/h2&gt;

&lt;p&gt;I normally use &lt;a href="https://github.com/Code52/carnac"&gt;Carnac&lt;/a&gt; on Windows to show my hotkeys and interactions with the Visual Studio editor while screencasting on Twitch or giving presentations. For my minimal approach on Linux, I added &lt;a href="https://gitlab.com/wavexx/screenkey"&gt;screenkey&lt;/a&gt; to handle this task for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install screenkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tuned the configuration slightly, primarily to ensure that it only showed the keystrokes that included modifier keys like Ctrl, Shift, or the Windows key. This helps prevent me from showing the world my password as I type it in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_Sj2NWX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_Sj2NWX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jeffreyfritz.com/wp-content/uploads/2020/03/image-1.png" alt="" width="539" height="547"&gt;&lt;/a&gt;screenkey configuration on my machine&lt;/p&gt;

&lt;h2&gt;
  
  
  Git command-prompt
&lt;/h2&gt;

&lt;p&gt;In Windows, I use the excellent posh-git to tell me the current start of my git repository when I’m working in a folder that has git-managed assets. For Linux, I installed the &lt;a href="https://github.com/magicmonty/bash-git-prompt"&gt;bash-git-prompt from magicmonty&lt;/a&gt; to improve the look of my terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/magicmonty/bash-git-prompt.git ~/.bash-git-prompt --depth=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then added this entry to my ~/.bashrc configuration for the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [-f "$HOME/.bash-git-prompt/gitprompt.sh"]; then
    GIT_PROMPT_ONLY_IN_REPO=1
    source $HOME/.bash-git-prompt/gitprompt.sh
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Now I have my source code status at the command-line. It could look cooler, but for a default configuration it works for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  tmux
&lt;/h2&gt;

&lt;p&gt;Next, I started using &lt;a href="https://github.com/tmux/tmux"&gt;tmux&lt;/a&gt;, the terminal multiplexer. This allows me to split my terminal window so that I can have multiple command-line experiences on-screen at once. I’m not too familiar with the configuration of tmux yet, and I know I can customize tmux to run the way that I want it to with the panels and colors tuned for me… but that’s a separate blog post.&lt;/p&gt;

&lt;p&gt;To get started, I launched tmux with the &lt;code&gt;tmux&lt;/code&gt;command and used the default configuration. I added two vertical panels to the right with the following keystrokes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl+b %
Ctrl+b "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then was able to shrink my right panel by hitting &lt;code&gt;Ctrl+b&lt;/code&gt; and HOLDING the &lt;code&gt;Ctrl&lt;/code&gt;key while I pressed the right-arrow key several times to make the panel the width I desired. See the image at the top of the article for the width I set mine to. This operation is tedious, and I really want to save it to a configuration file so that tmux just looks &lt;em&gt;RIGHT&lt;/em&gt; to me when I start it next time.&lt;/p&gt;

&lt;p&gt;I can move around the panels in tmux by using the &lt;code&gt;Ctrl+b &amp;lt;arrow-key&amp;gt;&lt;/code&gt; keystrokes in the direction I want to move the cursor. Note that you do NOT hold the &lt;code&gt;Ctrl&lt;/code&gt; key when you press the arrow keys when executing this gesture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Panel Configurations
&lt;/h2&gt;

&lt;p&gt;In my configuration, I set the larger left-panel for my code editing experience. The top-right panel will run my webserver with the &lt;code&gt;dotnet watch run&lt;/code&gt; command so that I can see the logs and I can restart it without impacting the rest of my configuration.&lt;/p&gt;

&lt;p&gt;The lower-right panel will run my unit-tests with the &lt;code&gt;dotnet watch test&lt;/code&gt; command. This way, as I change my code in the left panel, my tests automatically re-run and I know if I broke anything.&lt;/p&gt;

&lt;p&gt;I think I need some scripts to automate these panels and I may change their font-size as well as move them around a little to make it easier to see all of the logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;I’ve got a serviceable configuration at this point. I can build and run .NET Core, Blazor, and ASP.NET Core applications in Linux all at the command line. There are so many things that I can configure to automate and make my development easier, but at this point I feel like I have assembled my very own “Command-Line Visual Studio”.&lt;/p&gt;

&lt;p&gt;I want to archive the git commands that I used to fetch my vim plugins and store my .vimrc on GitHub so that I can fetch them on other machines that I want to replicate this experience on.&lt;/p&gt;

&lt;p&gt;The color and font themes in my console are not the most appealing to me. I’d really like to install Cascadia Code, a fresh vim color theme, and get that tmux configuration under control. The command-line for git could look better and I’d like to see some other status information on the tmux status bar. But that… is another blog post and Twitch session.&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>git</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>What’s Old is New Again – Web Forms meets Blazor</title>
      <dc:creator>Jeffrey T. Fritz</dc:creator>
      <pubDate>Mon, 06 Jan 2020 20:55:15 +0000</pubDate>
      <link>https://dev.to/csharpfritz/what-s-old-is-new-again-web-forms-meets-blazor-10b4</link>
      <guid>https://dev.to/csharpfritz/what-s-old-is-new-again-web-forms-meets-blazor-10b4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CPHFCXmQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jeffreyfritz.com/wp-content/uploads/2020/01/20190507_000103550_iOS.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CPHFCXmQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jeffreyfritz.com/wp-content/uploads/2020/01/20190507_000103550_iOS.jpg" alt=""&gt;&lt;/a&gt;BLAZOR!&lt;/p&gt;

&lt;p&gt;I live for these types of conversations: “Hey, is there a way to upgrade my application to the new framework?” The answer is almost ALWAYS no, because the person asking me has already searched the web and is looking for some secret upgrade technique from me. This time, this conversation, well it was a bit more interesting.&lt;/p&gt;

&lt;p&gt;“Hey Jeff, Blazor Server-Side and ASP.NET Web Forms are pretty similar in concepts. They both render code on the server and both have a component-based model. Is there a way we could somehow re-use markup between the two frameworks?” That question not only got my interest, but also started some interest with my colleague Dan Roth. We were planning to go on stage at Microsoft Ignite 2019 and talk about Blazor for Web Form developers… when Dan had the idea: “What if we had a shim, a component library that LOOKED and rendered HTML like the original ASP.NET controls? That could help with migration.”&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept
&lt;/h2&gt;

&lt;p&gt;The idea is simple: ASP.NET Web Forms is not available to develop with .NET Core, but Blazor is. &lt;em&gt;What if we could make it as simple as possible to copy your ASPX markup into a Blazor project and get the same markup delivered to the browser?&lt;/em&gt; We don’t want to enable developers to continue to develop with the same model, but to get their applications using the same UI, the same presentation that they’ve been using for years and a path forward. That is the goal.&lt;/p&gt;

&lt;p&gt;This would require some components, some shims and maybe some trickery to make the default components from the Web Forms framework work. With that, we set out to try to make something simple as a proof of concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Proof of Concept
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/0bQi4tkD3Ck"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
 Dan and I talk about the Blazor framework and what it means for Web Forms developers in a segment starting at 2:03:00 from Microsoft Ignite Live 2019 



&lt;p&gt;There are MILLIONS of ASP.NET Web Forms applications out there, and in our sample we showed an application with a few controls in use, but targeted this implementation &lt;a href="https://github.com/csharpfritz/eShopBlazor/blob/finished_demo/src/eShopLegacyWebForms/Default.aspx"&gt;(original source available)&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;asp:ListView ID="productList" runat="server" 
    ItemPlaceholderID="itemPlaceHolder" ItemType="eShopLib.CatalogItem"&amp;gt;
    &amp;lt;EmptyDataTemplate&amp;gt;
        &amp;lt;table&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;td&amp;gt;No data was returned.&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/table&amp;gt;
    &amp;lt;/EmptyDataTemplate&amp;gt;
    &amp;lt;LayoutTemplate&amp;gt;
        &amp;lt;table class="table"&amp;gt;
            &amp;lt;thead&amp;gt;
                &amp;lt;tr class="esh-table-header"&amp;gt;
                    &amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
                    &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
                    &amp;lt;!-- SNIP --&amp;gt;
                &amp;lt;/tr&amp;gt;
            &amp;lt;/thead&amp;gt;
            &amp;lt;tbody&amp;gt;
                &amp;lt;asp:PlaceHolder runat="server" ID="itemPlaceHolder"&amp;gt;&amp;lt;/asp:PlaceHolder&amp;gt;
            &amp;lt;/tbody&amp;gt;
        &amp;lt;/table&amp;gt;
    &amp;lt;/LayoutTemplate&amp;gt;
    &amp;lt;ItemTemplate&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;
                &amp;lt;image class="esh-thumbnail" src='/Pics/&amp;lt;%#:Item.PictureFileName%&amp;gt;' /&amp;gt;
            &amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;%#:Item.Name%&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;!-- SNIP --&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/ItemTemplate&amp;gt;
&amp;lt;/asp:ListView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a &lt;code&gt;ListView&lt;/code&gt; being used to present a table of products with Edit, Details, and Delete links on the side. (For this article, I’ve trimmed the width of the table for readability.) Dan replicated the capabilities of this control using a custom Blazor component, also called &lt;code&gt;ListView&lt;/code&gt; and we used this code to present the same UI but with Blazor &lt;a href="https://github.com/csharpfritz/eShopBlazor/blob/finished_demo/src/eShopOnBlazor/Pages/Index.razor"&gt;(original source)&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ListView Items="Model.Data" TItem="CatalogItem"&amp;gt;
    &amp;lt;EmptyDataTemplate&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;No data was returned.&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/EmptyDataTemplate&amp;gt;
    &amp;lt;TableHeader&amp;gt;
        &amp;lt;tr class="esh-table-header"&amp;gt;
            &amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
            &amp;lt;!-- SNIP --&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/TableHeader&amp;gt;
    &amp;lt;RowTemplate Context="catalogItem"&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;
                &amp;lt;img class="esh-thumbnail" src="@($"/Pics/{catalogItem.PictureFileName}")"&amp;gt;
            &amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;
                &amp;lt;p&amp;gt;@catalogItem.Name&amp;lt;/p&amp;gt;
            &amp;lt;/td&amp;gt;
            &amp;lt;!-- SNIP --&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/RowTemplate&amp;gt;
&amp;lt;/ListView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The tags are similar, the inner templates behave the same but have different names, and the formatting of the content inside the templates is &lt;em&gt;ALMOST&lt;/em&gt; identical save for the change from &lt;code&gt;&amp;lt;% %&amp;gt;&lt;/code&gt; notation to &lt;code&gt;@( )&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What If…
&lt;/h2&gt;

&lt;p&gt;What if we could make this conversion even closer? I took some next steps and improved the capabilities of the &lt;code&gt;ListView&lt;/code&gt; component so that we could now have this code output the same content as above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table class="table"&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr class="esh-table-header"&amp;gt;
            &amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
            &amp;lt;!-- SNIP --&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
      &amp;lt;ListView @ref="productList" runat="server" Context="Item"
          ItemPlaceholderID="itemPlaceHolder" ItemType="eShopLib.CatalogItem"&amp;gt;
          &amp;lt;EmptyDataTemplate&amp;gt;
                  &amp;lt;tr&amp;gt;
                      &amp;lt;td&amp;gt;No data was returned.&amp;lt;/td&amp;gt;
                  &amp;lt;/tr&amp;gt;
          &amp;lt;/EmptyDataTemplate&amp;gt;
          &amp;lt;ItemTemplate&amp;gt;
              &amp;lt;tr&amp;gt;
                  &amp;lt;td&amp;gt;
                      &amp;lt;image class="esh-thumbnail" src='/Pics/@Item.PictureFileName' /&amp;gt;
                  &amp;lt;/td&amp;gt;
                  &amp;lt;td&amp;gt;@Item.Name&amp;lt;/td&amp;gt;
                  &amp;lt;!-- SNIP --&amp;gt;
              &amp;lt;/tr&amp;gt;
          &amp;lt;/ItemTemplate&amp;gt;
      &amp;lt;/ListView&amp;gt;
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we’re talking! By moving the &lt;code&gt;LayoutTemplate&lt;/code&gt; content outside the &lt;code&gt;ListView&lt;/code&gt; component, the rest of the &lt;code&gt;ItemTemplate&lt;/code&gt; looks very similar. Almost all of the attributes on the &lt;code&gt;ListView&lt;/code&gt; component are the SAME, with the only exception is the id attribute being renamed to &lt;code&gt;@ref&lt;/code&gt;. The only addition is the &lt;code&gt;Context&lt;/code&gt; attribute so that the &lt;code&gt;Item&lt;/code&gt; object could be used in our templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Next?
&lt;/h2&gt;

&lt;p&gt;We think there’s an opportunity to make open source components to help facilitate this type of copy and paste conversion from simple Web Forms and controls. We’re just at the beginning of this process, but have opened a &lt;a href="https://github.com/FritzAndFriends/BlazorWebFormsComponents"&gt;project on GitHub&lt;/a&gt; to analyze and work through these controls. This is NOT a Microsoft supported project, but rather a concept that I and my community of friends are working through to see what benefit it could have.&lt;/p&gt;

&lt;p&gt;I have been diligently working on these components live on &lt;a href="https://twitch.tv/csharpfritz"&gt;my Twitch stream&lt;/a&gt;, and have taken time off camera to work on documentation, samples, and some general clean up work.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LiveView&lt;/code&gt;, &lt;code&gt;Repeater&lt;/code&gt;, and &lt;code&gt;DataList&lt;/code&gt; are all under construction as of the writing of this article. Simple ModelBinding to read and present data, data binding by specifying a &lt;code&gt;DataSource&lt;/code&gt; all works with these controls. We’ve even added obsolete warnings if you copy over code that contains &lt;code&gt;ViewState&lt;/code&gt; or &lt;code&gt;runat="server"&lt;/code&gt; references.&lt;/p&gt;

&lt;p&gt;The components are packaged using &lt;a href="https://dev.azure.com/FritzAndFriends/BlazorWebFormsComponents"&gt;Azure DevOps&lt;/a&gt; and deployed &lt;a href="https://www.nuget.org/packages/Fritz.BlazorWebFormsComponents"&gt;NuGet as the Fritz.BlazorWebFormsComponents package&lt;/a&gt; If this is something that you are interested in seeing grow and give these older applications new life, please open some issues or send a pull request.&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>dotnet</category>
      <category>blazor</category>
    </item>
  </channel>
</rss>
