<?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: Simon Reynolds</title>
    <description>The latest articles on DEV Community by Simon Reynolds (@simonreynolds).</description>
    <link>https://dev.to/simonreynolds</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%2F5698%2F7Mttzm0-.jpg</url>
      <title>DEV Community: Simon Reynolds</title>
      <link>https://dev.to/simonreynolds</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simonreynolds"/>
    <language>en</language>
    <item>
      <title>Announcing EFCore.FSharp</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Sun, 21 Mar 2021 15:05:49 +0000</pubDate>
      <link>https://dev.to/simonreynolds/announcing-efcore-fsharp-c6d</link>
      <guid>https://dev.to/simonreynolds/announcing-efcore-fsharp-c6d</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_NSBHQjo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1483736762161-1d107f3c78e1%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_NSBHQjo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1483736762161-1d107f3c78e1%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Announcing EFCore.FSharp" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today marks the first alpha release of F# support for Entity Framework Core, allowing for direct usage of EF Core from your F# projects with support for EF Core 5.0.3&lt;br&gt;&lt;br&gt;
It contains support for migrations and reverse-engineering, allowing you to map tables to F# records and take advantage of F# idioms such as &lt;code&gt;option&lt;/code&gt; to represent nullable columns. At the moment though, this does not work for primary or foreign keys, just plain columns (&lt;a href="https://github.com/efcore/EFCore.FSharp/issues/29"&gt;GitHub issue&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To take it for a test drive, grab the NuGet package from &lt;a href="https://www.nuget.org/packages/EntityFrameworkCore.FSharp"&gt;https://www.nuget.org/packages/EntityFrameworkCore.FSharp&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Bear in mind that it is an alpha release so please log any issues on the &lt;a href="https://github.com/efcore/EFCore.FSharp"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Currently it has support for relatively simple schemas, it does not support many-types-per-table relationships yet but that is &lt;a href="https://github.com/efcore/EFCore.FSharp/issues/21"&gt;on the to-do list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although it does support &lt;code&gt;option&lt;/code&gt; columns it does not yet support types such as discriminated unions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;All the usual ways of grabbing a NuGet package...&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Install-Package EntityFramworkCore.FSharp&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;dotnet add package EntityFramworkCore.FSharp&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;paket install EntityFramworkCore.FSharp&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;When it is installed, you will need to register it for &lt;code&gt;dotnet ef&lt;/code&gt; to pick it up. Simply add the following code to your project. It will be detected at compile time, no need to call it from a  &lt;code&gt;Startup&lt;/code&gt; class&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;DesignTimeServices&lt;/span&gt;

&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DependencyInjection&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Design&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FSharp&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;DesignTimeServices&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IDesignTimeServices&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; 
        &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;ConfigureDesignTimeServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IServiceCollection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fSharpServices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;EFCoreFSharpServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;
            &lt;span class="n"&gt;fSharpServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConfigureDesignTimeServices&lt;/span&gt; &lt;span class="n"&gt;serviceCollection&lt;/span&gt;
            &lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Migrations&lt;/p&gt;

&lt;p&gt;Code first databases are supported, a working example of creating a basic MVC application in F# with user authentication is available at &lt;a href="https://github.com/simon-reynolds/EFCore.FSharp.MvcAuth"&gt;https://github.com/simon-reynolds/EFCore.FSharp.MvcAuth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing to remember is that record types have to have the &lt;code&gt;[&amp;lt;CliMutable&amp;gt;]&lt;/code&gt; attribute specified so that they can be created correctly by Entity Framework.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;dotnet ef migration add&lt;/code&gt; you will need to add the created files to your your project. The migration files are generated sequentially so you can add a single glob reference to your fsproj file to add them all at once&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;Compile&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Migrations/*.fs"&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;There is an &lt;a href="https://github.com/efcore/EFCore.FSharp/issues/20"&gt;issue&lt;/a&gt; to track this to try find an automated solution. As always, any help or suggestions are welcome.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scaffolding
&lt;/h3&gt;

&lt;p&gt;When scaffolding a model from an existing database, we can specify how we want the generated code to be created in our &lt;code&gt;DesignTimeServices&lt;/code&gt; type above.&lt;/p&gt;

&lt;p&gt;We can create types as either record types or classes similar to how they behave in C#&lt;/p&gt;

&lt;p&gt;For instance, given a blog post type with an Id, Title and Content, it can generated as either example below.&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Record type&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;BlogPost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="nc"&gt;Content&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="c1"&gt;// Class type&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;BlogPost&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DefaultValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DefaultValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;

    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DefaultValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;._&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Similarly, optional columns can either be rendered as &lt;code&gt;Nullable&amp;lt;'a&amp;gt;&lt;/code&gt; or as &lt;code&gt;'a option&lt;/code&gt;. The default configuration will create record types with nullable columns specified as &lt;code&gt;option&lt;/code&gt; types.&lt;/p&gt;

&lt;p&gt;These are done by defining our scaffold options and passing them into the &lt;code&gt;DesignTimeServices&lt;/code&gt;, e.g.&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;DesignTimeServices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DependencyInjection&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Design&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FSharp&lt;/span&gt;

    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;DesignTimeServices&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IDesignTimeServices&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
            &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;ConfigureDesignTimeServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IServiceCollection&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 default behaviour can be specified by calling&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fSharpServices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;EFCoreFSharpServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;

                &lt;span class="c1"&gt;// Or we can define a ScaffoldOptions use that instead&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;scaffoldOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                    &lt;span class="nc"&gt;ScaffoldOptions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nc"&gt;ScaffoldTypesAs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ScaffoldTypesAs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClassType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;ScaffoldNullableColumnsAs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ScaffoldNullableColumnsAs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NullableTypes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fSharpServices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;EFCoreFSharpServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WithScaffoldOptions&lt;/span&gt; &lt;span class="n"&gt;scaffoldOptions&lt;/span&gt;

                &lt;span class="n"&gt;fSharpServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConfigureDesignTimeServices&lt;/span&gt; &lt;span class="n"&gt;serviceCollection&lt;/span&gt;
                &lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;More details can be found in our project documentation &lt;a href="https://efcore.github.io/EFCore.FSharp//How_Tos/Scaffold_As_Types.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Option types
&lt;/h3&gt;

&lt;p&gt;It has basic support for &lt;code&gt;option&lt;/code&gt; types, including an &lt;code&gt;OptionConverter&lt;/code&gt; for mapping nullable columns to options. When building a code first database simply include the following at the end of &lt;code&gt;OnModelCreating&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;MyContext&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
    &lt;span class="k"&gt;inherit&lt;/span&gt; &lt;span class="nc"&gt;DbContext&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OnModelCreating&lt;/span&gt; &lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="c"&gt;(* Define entities here *)&lt;/span&gt;

        &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RegisterOptionTypes&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other issues
&lt;/h3&gt;

&lt;p&gt;I'm sure there are. Please report any issues you discover and help us improve F# support for Entity Framework Core!&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>efcore</category>
      <category>dotnet</category>
      <category>sql</category>
    </item>
    <item>
      <title>Azure Storage Explorer and Multi-Factor Authentication</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Wed, 30 Sep 2020 11:49:17 +0000</pubDate>
      <link>https://dev.to/simonreynolds/azure-storage-explorer-and-multi-factor-authentication-2b1f</link>
      <guid>https://dev.to/simonreynolds/azure-storage-explorer-and-multi-factor-authentication-2b1f</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ibj5I90v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1509822929063-6b6cfc9b42f2%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ibj5I90v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1509822929063-6b6cfc9b42f2%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Azure Storage Explorer and Multi-Factor Authentication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use multi-factor authentication for all azure accounts and access at $EMPLOYER, because of course we do (and you should too). Being hacked isn't fun at the best of times, having your azure account being hacked is a quick route to a whole (and expensive) world of pain.&lt;/p&gt;

&lt;p&gt;This is great and provides a lot of extra security. But it's also a massive pain in the ass when you have multiple subscriptions and need to do the whole username, password, MFA challenge on &lt;em&gt;every&lt;/em&gt; subscription when you open Azure Storage Explorer.&lt;/p&gt;

&lt;p&gt;To get around this, click Edit -&amp;gt; Settings and select the following option:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Microsoft Authentication Library (Preview)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wS0aRs6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simontaite.com/content/images/2020/09/AzureStorageExplorer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wS0aRs6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simontaite.com/content/images/2020/09/AzureStorageExplorer.png" alt="Azure Storage Explorer and Multi-Factor Authentication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then restart Azure Storage Explorer and authenticate one last time. Now your subscriptions will remain signed in across restarts and when you open Storage Explorer you can get straight to what you want to do instead of yet another round of approving multiple sign in requests.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>authentication</category>
    </item>
    <item>
      <title>WTF is a Computation Expression...</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Mon, 20 Jul 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/wtf-is-a-computation-expression-5e7a</link>
      <guid>https://dev.to/simonreynolds/wtf-is-a-computation-expression-5e7a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZoxUdW83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1477313372947-d68a7d410e9f%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZoxUdW83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1477313372947-d68a7d410e9f%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="WTF is a Computation Expression..."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...and why should I care?&lt;/p&gt;

&lt;p&gt;Every time computation expressions in F# are discussed it's only a matter of time before the dreaded M-word is mentioned. So let's get it out of the way early....&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Monad&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Right, that's that done and let's not mention it again. Suffice to say, they're an interesting concept with no equivalent in C# and no necromancy is required to use or make them.&lt;/p&gt;

&lt;p&gt;If you've done any async work in F# or anything involving sequences then odds are you've already used a computation expression (CE).&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mySequence&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"First Item"&lt;/span&gt;
        &lt;span class="s2"&gt;"Second Item"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;myAsyncThing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DoTheAsyncThing&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The F# compiler has no built-in tricks or optimisations for these, they're just plain computation expressions, just like you can write too!&lt;/p&gt;

&lt;p&gt;Every computation expression needs a backing builder class, usually named after the computation, so &lt;code&gt;async&lt;/code&gt; would have a builder of type &lt;code&gt;AsyncBuilder&lt;/code&gt;. All it has to do to be used as a CE is implement certain methods, which map to particular keywords inside a CE.&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Typical signature(s)&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bind&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M&amp;lt;'T&amp;gt; * ('T -&amp;gt; M&amp;lt;'U&amp;gt;) -&amp;gt; M&amp;lt;'U&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;let!&lt;/code&gt; and &lt;code&gt;do!&lt;/code&gt; in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(unit -&amp;gt; M&amp;lt;'T&amp;gt;) -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wraps a computation expression as a function.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'T -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;return&lt;/code&gt; in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReturnFrom&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;return!&lt;/code&gt; in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt; or &lt;code&gt;M&amp;lt;'T&amp;gt; -&amp;gt; 'T&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Executes a computation expression.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Combine&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;M&amp;lt;'T&amp;gt; * M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt; or &lt;code&gt;M&amp;lt;unit&amp;gt; * M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Called for sequencing in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;For&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;seq&amp;lt;'T&amp;gt; * ('T -&amp;gt; M&amp;lt;'U&amp;gt;) -&amp;gt; M&amp;lt;'U&amp;gt;&lt;/code&gt; or &lt;code&gt;seq&amp;lt;'T&amp;gt; * ('T -&amp;gt; M&amp;lt;'U&amp;gt;) -&amp;gt; seq&amp;lt;M&amp;lt;'U&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;for...do&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TryFinally&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M&amp;lt;'T&amp;gt; * (unit -&amp;gt; unit) -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;try...finally&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TryWith&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M&amp;lt;'T&amp;gt; * (exn -&amp;gt; M&amp;lt;'T&amp;gt;) -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;try...with&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Using&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'T * ('T -&amp;gt; M&amp;lt;'U&amp;gt;) -&amp;gt; M&amp;lt;'U&amp;gt; when 'T :&amp;gt; IDisposable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;use&lt;/code&gt; bindings in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;While&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(unit -&amp;gt; bool) * M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;while...do&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yield&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'T -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;yield&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YieldFrom&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M&amp;lt;'T&amp;gt; -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for &lt;code&gt;yield!&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;&lt;code&gt;unit -&amp;gt; M&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called for empty &lt;code&gt;else&lt;/code&gt; branches of &lt;code&gt;if...then&lt;/code&gt; expressions in computation expressions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Quotations.Expr&amp;lt;'T&amp;gt; -&amp;gt; Quotations.Expr&amp;lt;'T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Indicates that the computation expression is passed to the Run member as a quotation. It translates all instances of a computation into a quotation.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now that all looks complicated so let's take a quick look at what advantages a CE gives us over writing plain code.&lt;/p&gt;

&lt;p&gt;Let's consider an example where we need to pass an item through several validation checks&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SomeThingThatNeedsValidating&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Each validation methhod has signature Item -&amp;gt; Result&amp;lt;Item, Error&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;firstValidation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;firstValidationCheck&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;secondValidation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;firstValidation&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;secondValidationCheck&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;thirdValidation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;secondValidation&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;thirdValidationCheck&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You probably look at that and think there must be a better way to write that. And you'd be right, this is a great example where we can use a computation expression.&lt;/p&gt;

&lt;p&gt;To build it, let's look at the &lt;code&gt;Result&lt;/code&gt; type and see if it has anything that can help us.&lt;/p&gt;

&lt;p&gt;There is already a &lt;code&gt;Result.bind&lt;/code&gt; that does the same as the &lt;code&gt;match&lt;/code&gt; statements above, so let's use that instead of reinventing the wheel.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="c1"&gt;// This can be used in a CE via the let! keyword&lt;/span&gt;
    &lt;span class="c1"&gt;// Result&amp;lt;'a,'b&amp;gt; * ('a -&amp;gt; Result&amp;lt;'c,'d&amp;gt;) -&amp;gt; Result&amp;lt;'c,'d&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;Bind&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;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;

    &lt;span class="c1"&gt;// This can be used in a CE via the return keyword&lt;/span&gt;
    &lt;span class="c1"&gt;// 'a -&amp;gt; Result&amp;lt;'a, 'b&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;Return&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;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;// This exposes the builder type as a computation expression&lt;/span&gt;
&lt;span class="c1"&gt;// It's what allows to use it like below...&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Short, sharp and to the point, right? But now we can express the validation checks above like this...&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SomeThingThatNeedsValidating&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;validatedItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// result here is the created instance of ResultBuilder from above&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;firstCheck&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;firstValidationCheck&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;secondCheck&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secondValidationCheck&lt;/span&gt; &lt;span class="n"&gt;firstCheck&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;thirdCheck&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thirdValidationCheck&lt;/span&gt; &lt;span class="n"&gt;secondCheck&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;thirdCheck&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of this approach is that the &lt;code&gt;let!&lt;/code&gt; keyword will only bind the successful validation and allow the CE to continue evaluating. If an error is returned from any of the validation checks then the entire CE will short circuit and return that error immediately.&lt;/p&gt;

&lt;p&gt;Congratulations, you now have a basic working CE of your very own! But a lot of that code looks like we shouldn't need it. Why assign each intermediate result to a variable along the way, surely we should just be able to pipe each step in to the next, right?&lt;/p&gt;

&lt;p&gt;Let's  add two further items to where we create our &lt;code&gt;ResultBuilder&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// F# allows us to define our own operators&lt;/span&gt;
&lt;span class="c1"&gt;// By convention, &amp;gt;&amp;gt;= usually refers to a bind method&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="o"&gt;(&amp;gt;&amp;gt;=)&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="n"&gt;binder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;binder&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="c1"&gt;// This can be used in a CE via the let! keyword&lt;/span&gt;
    &lt;span class="c1"&gt;// Result&amp;lt;'a,'b&amp;gt; * ('a -&amp;gt; Result&amp;lt;'c,'d&amp;gt;) -&amp;gt; Result&amp;lt;'c,'d&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;Bind&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;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;

    &lt;span class="c1"&gt;// This can be used in a CE via the return keyword&lt;/span&gt;
    &lt;span class="c1"&gt;// 'a -&amp;gt; Result&amp;lt;'a, 'b&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;Return&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;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

    &lt;span class="c1"&gt;// This can be used in a CE via the return! keyword&lt;/span&gt;
    &lt;span class="c1"&gt;// Result&amp;lt;'a, 'b&amp;gt; -&amp;gt; Result&amp;lt;'a, 'b&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;__.&lt;/span&gt;&lt;span class="nc"&gt;ReturnFrom&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;x&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResultBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can chain together our validation checks and it becomes a lot easier to be able to add new checks, compose smaller ones together, or reorder them without having to rename every variable along the way.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SomeThingThatNeedsValidating&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;validatedItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
            &lt;span class="n"&gt;firstValidationCheck&lt;/span&gt; &lt;span class="n"&gt;itemToValidate&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;secondValidationCheck&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;thirdValidationCheck&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we found we needed an extra check that should be between &lt;code&gt;secondValidationCheck&lt;/code&gt; and &lt;code&gt;thirdValidationCheck&lt;/code&gt;, it is as simple as adding it in.&lt;/p&gt;

&lt;p&gt;Hopefully this has helped to show you the power of a computation expression and that they aren't as scary as they first seemed. Of course this was a relatively simple example but from here you can see how they can be extended with additional functionality and even custom keywords that can be used to create miniature programming languages to solve problems. More to come on that front....&lt;/p&gt;

</description>
      <category>fsharp</category>
    </item>
    <item>
      <title>Hosting multiple web applications in Docker</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Tue, 07 Jul 2020 13:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/hosting-multiple-web-applications-in-docker-107d</link>
      <guid>https://dev.to/simonreynolds/hosting-multiple-web-applications-in-docker-107d</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vCXBGYZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1511578194003-00c80e42dc9b%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vCXBGYZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1511578194003-00c80e42dc9b%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Hosting multiple web applications in Docker" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've written before about &lt;a href="https://simontaite.com/hosting-multiple-web-applications-in-docker/developing-in-a-docker-container"&gt;developing software in Docker containers&lt;/a&gt; and while that has been a step forward for development and being able to isolate development environments, the strength of Docker has always been in running applications without having to worry about requirements or dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kX2S_nqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://SimonReynolds.ie/content/images/2020/07/Docker.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kX2S_nqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://SimonReynolds.ie/content/images/2020/07/Docker.jpg" alt="Hosting multiple web applications in Docker" width="422" height="585"&gt;&lt;/a&gt;How it all began...&lt;/p&gt;

&lt;p&gt;For managing clusters of applications we have plenty of options, Kubernetes, Docker Swarm, OpenStack and of course Docker Compose.&lt;/p&gt;

&lt;p&gt;Options like Kubernetes are indispensable when operating at scale, with dozens, hundreds or even thousands of instances of multiple microservices all working together to provide a full application.&lt;/p&gt;

&lt;p&gt;But when it comes to something like hosting a personal blog like this one then it can be overkill. Something simpler like Docker Compose will do just fine.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.1'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ghost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost:alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1:2368:2368&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./content:/var/lib/ghost/content&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.production.json:/var/lib/ghost/config.production.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;This is a relatively simple example of a docker-compose.yml file but it shows the important details, we specify our image, it's set to restart automatically in case of a crash or failure and mounts some files from the native file system and forwards to a port on the server itself.&lt;/p&gt;

&lt;p&gt;This is where we can set up a reverse proxy in nginx, but why install it when nginx is available as a docker image?&lt;/p&gt;

&lt;p&gt;Particularly when we have the chance to use this amazing piece of work?&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/evertramos"&gt;
        evertramos
      &lt;/a&gt; / &lt;a href="https://github.com/evertramos/nginx-proxy-automation"&gt;
        nginx-proxy-automation
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Automated docker nginx proxy integrated with letsencrypt.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;It sits between one or more docker containers and the outside world, forwarding requests and also taking care of SSL certificates using LetsEncrypt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JgLE9A06--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simontaite.com/content/images/2020/07/webproxy-1-.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JgLE9A06--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simontaite.com/content/images/2020/07/webproxy-1-.jpg" alt="Hosting multiple web applications in Docker" width="873" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To host our ghost blog behind it all we need to do is expand our docker-compose file and restart that container. The nginx proxy will detect it based on the extra environment variables and handle all proxy reversing and add your new SSL certificates.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.1'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ghost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost:alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1:2368:2368&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./content:/var/lib/ghost/content&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.production.json:/var/lib/ghost/config.production.json&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Note how VIRTUAL_HOST and LETSENCRYPT_HOST allow for multiple domains&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VIRTUAL_HOST=simonreynolds.ie,www.simonreynolds.ie&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LETSENCRYPT_HOST=simonreynolds.ie,www.simonreynolds.ie&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LETSENCRYPT_EMAIL=REDACTED@example.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MAIN_DOMAIN=simonreynolds.ie&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VIRTUAL_PORT=2368&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webproxy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I took the extra step of creating the &lt;code&gt;webproxy&lt;/code&gt; network myself so I can host multiple sites across different domains from just one server.&lt;/p&gt;

&lt;p&gt;This makes spinning up small sites for testing ideas incredibly easy and fully automates SSL certificates so I never have to worry about expired certificates again!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>nginx</category>
      <category>ssl</category>
    </item>
    <item>
      <title>SSRS Access woes</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Fri, 03 Jul 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/ssrs-access-woes-mcb</link>
      <guid>https://dev.to/simonreynolds/ssrs-access-woes-mcb</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1c_V2EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1579523360589-120f265e0988%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1c_V2EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1579523360589-120f265e0988%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="SSRS Access woes" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm writing this up for two reasons, one is that I can find this again next time it happens. The second is simple but important, we all make mistakes and at times they can seem pretty obvious in retrospect. But it's important to share the stories of our failures as well as our successes.&lt;/p&gt;

&lt;p&gt;We all do both but when we tend to only talk about our successes it can encourage feelings of &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome"&gt;impostor syndrome&lt;/a&gt; in others. So let's talk more about our mistakes. And on that note.....&lt;/p&gt;

&lt;p&gt;Picture the scene. It's been a long day but I'm about to release to production with some changes including moving our trusty old &lt;a href="https://docs.microsoft.com/en-us/sql/reporting-services/create-deploy-and-manage-mobile-and-paginated-reports?view=sql-server-ver15"&gt;SSRS&lt;/a&gt; server.&lt;/p&gt;

&lt;p&gt;A final double check, I can run reports fine in testing, I've updated firewall rules, I've changed the report server url in all the config files.... it all looks good!&lt;/p&gt;

&lt;p&gt;Then I deploy, everything is looking good, and I go to run a report....&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fMJehv6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2020/07/WorksOnMyMachine.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fMJehv6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2020/07/WorksOnMyMachine.png" alt="SSRS Access woes" width="635" height="634"&gt;&lt;/a&gt;The traditional mid-deployment cry of a programmer&lt;/p&gt;

&lt;p&gt;The moral of this story is simple:&lt;/p&gt;

&lt;h3&gt;
  
  
  CHECK YOUR DAMN CREDENTIALS
&lt;/h3&gt;

&lt;p&gt;Not all environments are using the same credentials and when I set them up in Site Settings, I forgot that I also need to click here too....&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8mcgGQZI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2020/07/Header.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8mcgGQZI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2020/07/Header.png" alt="SSRS Access woes" width="548" height="92"&gt;&lt;/a&gt;The simple cause of many problems&lt;/p&gt;

&lt;p&gt;In Folder Settings, click on New Role Assignment and add users here too! Give them the required permissions, e.g. Content Manager, and now they have permission to view and run reports. Voilà, suddenly all is as it should be and a full blown crisis has been averted.&lt;/p&gt;

</description>
      <category>failure</category>
      <category>deployment</category>
      <category>ssrs</category>
    </item>
    <item>
      <title>FsCheck: An introduction</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Tue, 30 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/fscheck-an-introduction-1fe4</link>
      <guid>https://dev.to/simonreynolds/fscheck-an-introduction-1fe4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Cv0h25v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1536875489903-655d152ed785%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Cv0h25v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1536875489903-655d152ed785%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="FsCheck: An introduction"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've all heard of unit testing and some of us have even been known to practice it. It has a simple premise&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a method or some other "unit" of code you want to test&lt;/li&gt;
&lt;li&gt;Pass in some contrived test data&lt;/li&gt;
&lt;li&gt;Compare the result to what you would expect it to be&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is essentially &lt;em&gt;example based testing&lt;/em&gt;. All we can guarantee with it is that the output is as expected for the given input. That may be a single case or a handful of test cases.&lt;/p&gt;

&lt;p&gt;If we were to imagine we had a requirement for a method that would reverse any given string of text then we could have a particularly obtuse developer who only wants to implement exactly what is in the requirement, no more and no less.&lt;/p&gt;

&lt;p&gt;If the requirement states&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;For example, a given string "abcdef" would be reversed to "fedcba"...&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;then it's possible that our developer may write something like this.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"String reverses correctly"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fedcba"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"abcdef"&lt;/span&gt;

    &lt;span class="nn"&gt;Expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="s2"&gt;"Should be equal"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This all looks straightforward enough until we look at the implementation of &lt;code&gt;reverse&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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="p"&gt;=&lt;/span&gt;
    &lt;span class="s2"&gt;"fdecba"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is clearly a contrived example but we can see how one test is not exhaustive. But what's the alternative? We clearly can't create a list of every possible string of text. Especially when we consider the amount of whitespace and non-printable characters.&lt;/p&gt;

&lt;p&gt;We need random input, this is where we need &lt;em&gt;property based testing&lt;/em&gt;. We can consider the properties of a method that would reverse a string.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The characters that make up the original string will all be in the reversed string, but in the opposite order&lt;/li&gt;
&lt;li&gt;So if we count each character in both, we should never have a character that only appears once&lt;/li&gt;
&lt;li&gt;Both strings should be the same length&lt;/li&gt;
&lt;li&gt;If we join the two strings into a new string, the same character should be repeated in the middle&lt;/li&gt;
&lt;li&gt;Reversing a string twice should give us the original again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reversing the string again is a useful test but by itself does not prove that the &lt;code&gt;reverse&lt;/code&gt; method is complete. After all if it just returned the string unchanged then the string would be the same after two calls to &lt;code&gt;reverse&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A more useful test would be to compare the reversed string and iterate backwards through each character. Each character should match if we were to iterate forwards through the original string.&lt;/p&gt;

&lt;p&gt;Let's use a property based testing framework called &lt;a href="https://fscheck.github.io/FsCheck/index.html"&gt;FsCheck&lt;/a&gt;. It allows us to test the assumptions in our methods and find edge cases we never even considered.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isNull&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;charArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToCharArray&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rev&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toArray&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charArray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;testList&lt;/span&gt; &lt;span class="s2"&gt;"ReversePropertyTests"&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;

        &lt;span class="n"&gt;testProperty&lt;/span&gt; &lt;span class="s2"&gt;"Char at index[length-n] of reversed string equals index[n] of original"&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;|&lt;/span&gt;
            &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isNull&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
                    &lt;span class="n"&gt;reversed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;
                    &lt;span class="c1"&gt;// Account for zero-based index&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reversedLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reversedAsArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToCharArray&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;input&lt;/span&gt;
                        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reversedAsArray&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="n"&gt;reversedLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
                        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;

       &lt;span class="c1"&gt;// This will likely fail, can you see why?&lt;/span&gt;
       &lt;span class="n"&gt;testProperty&lt;/span&gt; &lt;span class="s2"&gt;"Reversed string should have same length as original"&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;|&lt;/span&gt;
            &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
                &lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt;

       &lt;span class="c1"&gt;// Think about what other testProperty could be defined here&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This way, we are not testing any individual input. Instead FsCheck will, by default, run the test 100 times using progressively more complicated strings that include whitespace, line breaks, unprintable characters etc.&lt;/p&gt;

&lt;p&gt;If a test fails, the framework will then restrict the inputs it generates based on the failing tests to try identify ranges of failure. When a failure is encountered it will attempt to reduce the failure to the minimum changes from passing tests required for it to fail.&lt;/p&gt;

&lt;p&gt;In practice this means that if we were testing a method with DateTime parameters, it might be able to show us that there is an error in the method when dealing with dates in specific ranges or that only occur before or after particular dates.&lt;/p&gt;

&lt;p&gt;It is also very adaptable, we can create custom data generators, allowing us to create random data within ranges or of specific types. For instance, you may want to create random email addresses or some other constrained type.&lt;/p&gt;

&lt;p&gt;These are some of the properties we can test using a library like FsCheck. Obviously in this example the first property above is enough to define the method entirely but in more complex scenarios, it can be better to have a number of tests that each check an individual property of the scenario. An example of this is Mark Seemann's excellent &lt;a href="https://www.pluralsight.com/courses/fsharp-property-based-testing-introduction"&gt;Introduction to Property Based Testing&lt;/a&gt; on Pluralsight which utilises the &lt;a href="https://codingdojo.org/kata/Diamond/"&gt;Diamond Kata&lt;/a&gt; as a demonstration.&lt;/p&gt;

&lt;p&gt;FsCheck is a .NET library so although it is written in F# and primarily with the F# ecosystem in mind it can be used just as easily in C# or VB.NET. It uses a &lt;code&gt;PropertyAttribute&lt;/code&gt; or any custom attribute which inherits from it. Although the examples here are written using &lt;a href="https://github.com/haf/expecto"&gt;Expecto&lt;/a&gt; and its &lt;a href="https://www.nuget.org/packages/Expecto.FsCheck/"&gt;FsCheck plugin&lt;/a&gt;, there are also plugins for &lt;a href="https://www.nuget.org/packages/FsCheck.Xunit/"&gt;xUnit&lt;/a&gt; and &lt;a href="https://www.nuget.org/packages/FsCheck.Nunit/"&gt;NUnit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Property based testing is a different method of thinking about your tests but something well worth considering, especially for those areas of your codebase that seem to always have more edge cases every time you look at them. By making you stop and think about the more generalised properties of what the method should be doing it flushes those edge cases out into the light where they can be found.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>fscheck</category>
      <category>testing</category>
    </item>
    <item>
      <title>MiniScaffold, setting up a new F# project the easy way</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Fri, 26 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/miniscaffold-setting-up-a-new-f-project-the-easy-way-4dao</link>
      <guid>https://dev.to/simonreynolds/miniscaffold-setting-up-a-new-f-project-the-easy-way-4dao</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yZmgrrgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1588049089928-ceb048f61358%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yZmgrrgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1588049089928-ceb048f61358%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="MiniScaffold, setting up a new F# project the easy way"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting up a new project can be a pain. Especially if you want to split it into separate folders for clarity. You might want a &lt;code&gt;src&lt;/code&gt; folder for the project itself, a &lt;code&gt;test&lt;/code&gt; folder for the unit and integration tests, a &lt;code&gt;docs&lt;/code&gt; folder for documentation. You are writing documentation for your work, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XF7ZOzY0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://simonreynolds.ie/content/images/2020/06/giphy-1-.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XF7ZOzY0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://simonreynolds.ie/content/images/2020/06/giphy-1-.gif" alt="MiniScaffold, setting up a new F# project the easy way"&gt;&lt;/a&gt;Of course I always do too &lt;/p&gt;

&lt;p&gt;If you're writing in F# you've probably long ago moved from NuGet to Paket, but the standard .NET templates still use NuGet so that has to be migrated. There's build scripts to write too. It could be an hour or more of work before you start working on the code you actually wanted to write.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://github.com/TheAngryByrd/MiniScaffold/"&gt;MiniScaffold&lt;/a&gt;, a dotnet template that is for creating and publishing applications (supporting .NET Core 3.1) and libraries (supporting both .NETStandard 2.1 and .NET Framework 4.6.1&lt;/p&gt;

&lt;p&gt;It's designed and built to take care of the humdrum for you, it gives you&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a clean and well separated folder structure&lt;/li&gt;
&lt;li&gt;a matching &lt;code&gt;.gitignore&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;.editorconfig&lt;/code&gt; file tweaked for F# development&lt;/li&gt;
&lt;li&gt;configures CI builds on &lt;a href="https://www.appveyor.com/"&gt;Appveyor&lt;/a&gt; (for Windows) and &lt;a href="https://travis-ci.org/"&gt;TravisCI&lt;/a&gt; (for Linux and macOS)&lt;/li&gt;
&lt;li&gt;fully configured build scripts using &lt;a href="https://fake.build/"&gt;FAKE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;integrated package management with &lt;a href="https://fsprojects.github.io/Paket/"&gt;Paket&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;integrated unit testing (&lt;a href="https://github.com/haf/expecto"&gt;Expecto&lt;/a&gt;) and code coverage reports (&lt;a href="https://github.com/SteveGilham/altcover"&gt;AltCover&lt;/a&gt;/&lt;a href="https://github.com/danielpalme/ReportGenerator"&gt;ReportGenerator&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;automatic code formatting with &lt;a href="https://github.com/fsprojects/fantomas"&gt;Fantomas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's just to get started, also included is a file named &lt;code&gt;CHANGELOG.md&lt;/code&gt;. All you have to do is keep it updated with your notable changes, even reference the associated pull requests for those changes.&lt;/p&gt;

&lt;p&gt;The generated build scripts include a &lt;code&gt;Release&lt;/code&gt; action that will parse the &lt;code&gt;CHANGELOG.md&lt;/code&gt; file, create a tag in GitHub with the version number specified, update any pull requests mentioned with the version number, publish a GitHub release for the version and even include any build artifacts in the &lt;code&gt;dist&lt;/code&gt; folder! Doing all that is as easy as typing seven extra characters&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Development build&lt;/span&gt;
./build.sh

&lt;span class="c"&gt;# Release build&lt;/span&gt;
./build.sh Release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's certainly an opiniated template, if you really wanted to go with a different test library for example, you'd have enough repeated work changing it each time that it would probably be better to fork the &lt;a href="https://github.com/TheAngryByrd/MiniScaffold/"&gt;github project&lt;/a&gt; and customise it yourself. But I'd recommend trying it out first, it becomes second nature and is now my go to template for all F# projects!&lt;/p&gt;

&lt;p&gt;To get started, install the template&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"MiniScaffold::*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then go with&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# I'm building a library&lt;/span&gt;
dotnet new mini-scaffold &lt;span class="nt"&gt;-n&lt;/span&gt; MyCoolNewLib &lt;span class="nt"&gt;--githubUsername&lt;/span&gt; MyGithubUsername

&lt;span class="c"&gt;# I'm building an application&lt;/span&gt;
dotnet new mini-scaffold &lt;span class="nt"&gt;-n&lt;/span&gt; MyCoolNewApp &lt;span class="nt"&gt;--githubUsername&lt;/span&gt; MyGithubUsername &lt;span class="nt"&gt;-ou&lt;/span&gt; console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The author of this template, &lt;a href="https://www.jimmybyrd.me/"&gt;Jimmy Byrd&lt;/a&gt;, has clearly put an incredible amount of effort into this and it is a great example of how creating a template (or any project) to simplify some repetitive task is always worth sharing with the community.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Yet more "fun" with time zones in .NET</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Tue, 23 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/yet-more-fun-with-time-zones-in-net-3p8a</link>
      <guid>https://dev.to/simonreynolds/yet-more-fun-with-time-zones-in-net-3p8a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VHTAvlJ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1506686098657-5eeb165b4353%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VHTAvlJ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1506686098657-5eeb165b4353%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Yet more"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is a truth universally acknowledged, that a .NET project in possession of multiple time zones, must be in want of &lt;a href="https://nodatime.org/"&gt;Noda Time&lt;/a&gt;. Sometimes though, we have an existing project where it's just not reasonable to move everything over and we need a way to display a &lt;code&gt;DateTime&lt;/code&gt; in a time zone that may not necessarily be the local time zone.&lt;/p&gt;

&lt;p&gt;While .NET does include such types as &lt;code&gt;DateTimeOffset&lt;/code&gt;, an offset for UTC is not the same as a timezone. Time zones can and do change, including daylight saving changes. An offset from UTC does not reflect that and can be shared across many time zones.&lt;/p&gt;

&lt;p&gt;For instance, if we created a &lt;code&gt;DateTimeOffset&lt;/code&gt; with a UTC offset of +01:00, that could be Paris in winter (Central European Time), Dublin in summer (Irish Standard Time) or Lagos in Nigeria (West Africa Time) at any time of year since daylight saving is not observed there.&lt;/p&gt;

&lt;p&gt;Suppose instead that we have a system where the &lt;code&gt;DateTime&lt;/code&gt; has been saved as UTC and we now want to display it as a local time zone. If we have a given string &lt;code&gt;tzId&lt;/code&gt; representing our time zone then we can do the following...&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;DateTime&lt;/span&gt; &lt;span class="n"&gt;utc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
   &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertTimeFromUtc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tzId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're running .NET Framework then you're restricted to Windows and you can use the Windows time zones defined in the registry at &lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you're running .NET Core then it gets a little more complicated.&lt;/p&gt;

&lt;p&gt;On Windows hosts then it still uses the registry entries above, where for example Dublin, Ireland is represented as "GMT Standard Time". On Linux and macOS it uses the &lt;a href="https://en.wikipedia.org/wiki/Tz_database"&gt;tzdata&lt;/a&gt; format of "Europe/Dublin".&lt;/p&gt;

&lt;p&gt;This does make things awkward at the moment, particularly in Azure functions where you don't know what platform your code is going to be running on.&lt;/p&gt;

&lt;p&gt;If you know the time zone in advance you may consider something like&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;DateTime&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//This is for Linux&lt;/span&gt;
  &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertTimeFromUtc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Europe/Dublin"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeZoneNotFoundException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//This is for Windows&lt;/span&gt;
  &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertTimeFromUtc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GMT Standard Time"&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="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hardly elegant code.&lt;/p&gt;

&lt;p&gt;One option is to use the &lt;a href="https://www.nuget.org/packages/TimeZoneConverter"&gt;TimeZoneConverter&lt;/a&gt; library and combine it with a check of what platform we are executing on&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// using System.Runtime.InteropServices;&lt;/span&gt;
&lt;span class="c1"&gt;// using TimeZoneConverter;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="nf"&gt;GetLocalTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;utc&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;timeZone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isWindows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RuntimeInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsOSPlatform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OSPlatform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Windows&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;isWindows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timeZone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TZConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IanaToWindows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// There is also a TZConvert.WindowsToIana method for going the other way&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;local&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertTimeFromUtc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeZone&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;local&lt;/span&gt;&lt;span class="p"&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;utc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 2020-06-23 07:50&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timeZone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Europe/Dublin"&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;local&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetLocalTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2020-06-23 08:50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So there is a way around but time zones are still a bit of a mess when dealing with cross-platform code. There is a &lt;a href="https://github.com/dotnet/runtime/issues/14929"&gt;GitHub issue&lt;/a&gt; for aligning time zone identifiers across platforms in .NET Core so check it out and give a thumbs up if it would help you out.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>datetime</category>
      <category>timezones</category>
    </item>
    <item>
      <title>The continued theft of ideas by C#</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Fri, 19 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/the-continued-theft-of-ideas-by-c-3mcm</link>
      <guid>https://dev.to/simonreynolds/the-continued-theft-of-ideas-by-c-3mcm</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mKIrgDj_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1487795924438-a3cb4b7a5556%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mKIrgDj_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1487795924438-a3cb4b7a5556%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="The continued theft of ideas by C#"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back in the good old days, C# was .NET was Windows. Sure there were antique languages like VB.NET and ivory tower academia from F# but &lt;a href="https://xkcd.com/378/"&gt;&lt;em&gt;real&lt;/em&gt; developers&lt;/a&gt; used C# and the language was just fine as it was.&lt;/p&gt;

&lt;p&gt;Sure, some additions helped, generics were ok even if they did smell suspiciously like Java. But honestly, a lot of the newer "features" of C# are just syntactic sugar that don't really help anything.&lt;/p&gt;

&lt;p&gt;I mean, who really needs things like type inference or ternary operators? And that LINQ syntax?! Who can honestly claim that this&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;squaredValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intCollection&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;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;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is clearer and simpler than this?&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;squaredValues&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;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;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;intCollection&lt;/span&gt;&lt;span class="p"&gt;)&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;squared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;squaredValues&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="n"&gt;squared&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;But now, now it gets even worse! C# 8.0 has polluted the language with such unnecessary things as &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references"&gt;nullable reference types&lt;/a&gt;. Maybe I like spending hours hunting through code to track down why something is null when it shouldn't be.&lt;/p&gt;

&lt;p&gt;As if that wasn't bad enough, now we have new operators too! We have a fancy new "null-coalescing" operator where a simple if statement would suffice.&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mayBeNull&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="c1"&gt;// Who on earth would do this?&lt;/span&gt;
&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mustNotBeNull&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mayBeNull&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// When they can do this?&lt;/span&gt;
&lt;span class="c1"&gt;// What does it matter if someone forgets to do the if check&lt;/span&gt;
&lt;span class="c1"&gt;// when it's their tenth time writing code like this today?&lt;/span&gt;
&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mustNotBeNull&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mayBeNull&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;mustNotBeNull&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="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mustNotBeNull&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But worst of all now they've taken ideas from dangerously fringe languages like F#, with such strange concepts as Pattern Matching, even going so far as to be able to use them on tuples!&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;enum&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Rock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Paper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Scissors&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="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;RockPaperScissors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt; &lt;span class="n"&gt;second&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="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"rock is covered by paper. Paper wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scissors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"rock breaks scissors. Rock wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"paper covers rock. Paper wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scissors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"paper is cut by scissors. Scissors wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scissors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"scissors is broken by rock. Rock wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scissors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"scissors cuts paper. Scissors wins."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"tie"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If something like Rock, Paper, Scissors can be expressed in a single method that will even give a compiler warning if every possible combination isn't covered in the switch statement, then how on earth is a developer supposed to be able to justify a large design or testing budget?!&lt;/p&gt;

&lt;p&gt;But it gets even worse, the upcoming C# 9.0 is adding more features inspired by F#! Honestly, who has even heard of a &lt;a href="https://www.letsgetchecked.com/"&gt;successful&lt;/a&gt; &lt;a href="https://www.walmart.com/"&gt;company&lt;/a&gt; &lt;a href="https://www.olo.com/"&gt;using F#&lt;/a&gt; &lt;a href="https://www.carsales.com.au/"&gt;in production&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;But no, it had to take inspiration from this "language" (it doesn't even use semicolons). Adding such unnecessary new things as an &lt;code&gt;init&lt;/code&gt; accessor that allows you to specify that a property can only be written to at object initialisation.&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;Person&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;FirstName&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;LastName&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;var&lt;/span&gt; &lt;span class="n"&gt;simon&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;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Simon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reynolds"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Why does it matter that this code is legal?&lt;/span&gt;
&lt;span class="c1"&gt;// Surely we'd all just remember to not make this mistake?&lt;/span&gt;
&lt;span class="n"&gt;simon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Evan"&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;class&lt;/span&gt; &lt;span class="nc"&gt;Person2&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;FirstName&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="n"&gt;init&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;LastName&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="n"&gt;init&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;var&lt;/span&gt; &lt;span class="n"&gt;simon&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;Person2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Simon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reynolds"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Is having to learn a new accessor really worth avoiding mistakes like this?&lt;/span&gt;
&lt;span class="c1"&gt;// Who cares that this would be a compiler error instead of a bug report?&lt;/span&gt;
&lt;span class="n"&gt;simon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Arlo"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does it matter if a property is mutable and can be changed at any point? If it's not meant to be written to after creation then that's on us as developers to be professional enough to remember not to write to it!&lt;/p&gt;

&lt;p&gt;But still that's not enough, C# 9.0 goes further and introduces the idea of a class being an automatically immutable "record" class. Why on earth would anyone want an object that just represents data and is guaranteed not to be accidentally modified? Why would we need an object that is considered equal to another simply because all the properties of it have the same values?&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="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="c1"&gt;// What is this "data" keyword?!&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;FirstName&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="n"&gt;init&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;LastName&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="n"&gt;init&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="c1"&gt;// This is the same but what are we really gaining from this brevity?&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;FirstName&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;LastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Or even more extreme brevity?&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;FirstName&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;LastName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does it really help to compress 5 lines down to one? How does that make things simpler?&lt;/p&gt;

&lt;p&gt;What if we want to change a record? So instead of modifying it we just have to create a new one even though most fields will have the same values? How can that be done without having to copy each field manually?&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;simon&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Simon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Reynolds"&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;evan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simon&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Evan"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ("Evan", "Taite")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh.....ok, I guess that's pretty convenient. And granted, we got automatic deconstruction back into separate fields for free as well but still....this can't be that useful in real life scenarios, right?&lt;/p&gt;

&lt;p&gt;It's not as if there's an entire application architecture based on recording the entire history of an object at every point in its history instead of just updating a single instance of it, &lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing"&gt;right&lt;/a&gt;? Why would we ever need to audit our records and tell you &lt;em&gt;why, how or when&lt;/em&gt; a change occurred?&lt;/p&gt;

&lt;p&gt;C# needs to drop all &lt;a href="https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/"&gt;these new plans&lt;/a&gt; and return to its roots as a plain object-oriented language where anything can be null, state can be changed by anything and where dozens of if/else statements are used instead of single switches that cover all cases. If we carry on down this dangerous path how are we supposed to show our skills? Which will look more impressive, fixing a critical bug at 3AM on a Sunday morning or leaving work on time each day because we've been able to prevent the bug in the first place?&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>fsharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>PowerShell in .NET Core and Docker</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Tue, 16 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/simonreynolds/powershell-in-net-core-and-docker-23h2</link>
      <guid>https://dev.to/simonreynolds/powershell-in-net-core-and-docker-23h2</guid>
      <description>&lt;p&gt;Since the beginning of &lt;del&gt;time&lt;/del&gt;.NET Core there has been one continuous annoyance about developing cross-platform solutions, including build scripts for windows and non-windows platforms.&lt;/p&gt;

&lt;p&gt;We have at least fallen into a standard pattern, most repositories will contain both a &lt;code&gt;build.cmd&lt;/code&gt; and &lt;code&gt;build.sh&lt;/code&gt; that will build the project in whichever platform we're currently using.&lt;/p&gt;

&lt;p&gt;Sometimes though there's only one or one is neglected in favour of the other. If we're using a build tool like &lt;a href="https://cakebuild.net/"&gt;Cake&lt;/a&gt; or &lt;a href="https://fake.build/"&gt;Fake&lt;/a&gt; then we have a simple setup, our build files can just trigger the build logic which is stored in a single file. In fact, both tools will give you default build files that do just that.&lt;/p&gt;

&lt;p&gt;So what if we're just doing a relatively plain build task? Something like&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet clean

dotnet tool restore

dotnet build ./src/&lt;span class="k"&gt;*&lt;/span&gt;.csproj

dotnet build ./tests/&lt;span class="k"&gt;*&lt;/span&gt;.csproj

dotnet &lt;span class="nb"&gt;test&lt;/span&gt; ./tests/&lt;span class="k"&gt;*&lt;/span&gt;.csproj

dotnet package ./src/&lt;span class="k"&gt;*&lt;/span&gt;.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time changes will be made to this and human error is inevitable, a change will be made to &lt;code&gt;build.cmd&lt;/code&gt; but not to &lt;code&gt;build.sh&lt;/code&gt;, or vice versa.&lt;/p&gt;

&lt;p&gt;Enter PowerShell Core, now available as a &lt;code&gt;dotnet tool&lt;/code&gt;! Presuming you have the .NET Core SDK installed, you can simply run&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; PowerShell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will now be available with the &lt;code&gt;pwsh&lt;/code&gt; command. But this still presumes that other developers will have it installed globally.&lt;/p&gt;

&lt;p&gt;Let's add it on a project level.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# add a tool manifest if there isn't one already&lt;/span&gt;
dotnet new tool-manifest

dotnet tool &lt;span class="nb"&gt;install &lt;/span&gt;PowerShell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now PowerShell becomes a tool available in the project. Instead of &lt;code&gt;pwsh&lt;/code&gt;, you will have to specify &lt;code&gt;dotnet pwsh&lt;/code&gt; but now we can create a &lt;code&gt;build.ps1&lt;/code&gt; file that can contain all our build logic and replace our &lt;code&gt;build.cmd&lt;/code&gt; and &lt;code&gt;build.sh&lt;/code&gt; files with a one-liner.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet pwsh build.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all our build logic is cross-platform without external dependencies!&lt;/p&gt;

&lt;p&gt;Where this really comes into its own is that PowerShell has been included as a global tool in &lt;a href="https://hub.docker.com/_/microsoft-dotnet-core-sdk/"&gt;.NET Core SDK docker images&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Combined with Visual Studio Code's new Remote Development functionality, this means you can build a truly cross-platform development environment in a docker image. Simply &lt;a href="https://simonreynolds.ie/developing-in-a-docker-container/"&gt;set it up for your project&lt;/a&gt;, write one build script in PowerShell and rest secure in the knowledge that you're providing everything needed for another developer to be able to grab your project, open it up and build it immediately without having to worry about setting up dependencies or even what platform they're using!&lt;/p&gt;

</description>
      <category>netcore</category>
      <category>docker</category>
      <category>powershell</category>
    </item>
    <item>
      <title>Developing in a docker container</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Sat, 13 Jun 2020 13:26:56 +0000</pubDate>
      <link>https://dev.to/simonreynolds/developing-in-a-docker-container-54om</link>
      <guid>https://dev.to/simonreynolds/developing-in-a-docker-container-54om</guid>
      <description>&lt;p&gt;Ah, a new open source project that looks interesting. Let's pull it down from GitHub, open it up in the IDE of our choice and.... Oh... It turns out the build scripts assume you have some build tool already installed or, even worse, a specific version of it.&lt;/p&gt;

&lt;p&gt;This is a great example of where the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack"&gt;Remote Development&lt;/a&gt; extension pack for &lt;a href="https://code.visualstudio.com"&gt;Visual Studio Code&lt;/a&gt; comes in. Grab it and you can do all your development in a docker container for your projects!&lt;/p&gt;

&lt;p&gt;Naturally, you'll need to have Docker installed, either &lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker Desktop&lt;/a&gt; for Windows or MacOS, or &lt;a href="https://docs.docker.com/install/#supported-platforms"&gt;Docker CE/EE&lt;/a&gt; for the Linux distribution of your choosing.&lt;/p&gt;

&lt;p&gt;And in even better news, with the release of WSL 2, Docker now uses it instead of Hyper-V as the backend, so you can run Docker on Windows 10 Home Edition too! Read more about it &lt;a href="https://www.docker.com/blog/docker-hearts-wsl-2/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once that's installed all you need to add is a &lt;code&gt;.devcontainer&lt;/code&gt; folder in the root of your project and throw in a &lt;code&gt;devcontainer.json&lt;/code&gt; file. You can use it to either specify a prebuilt &lt;code&gt;image&lt;/code&gt; or specify a &lt;code&gt;DOCKERFILE&lt;/code&gt; that you can use to build a custom development environment.&lt;/p&gt;

&lt;p&gt;You can use this for any project in any language, I'm going to detail how I use it for a .NET Core project built in F# but the same ideas can be applied to any project.&lt;/p&gt;

&lt;p&gt;You can base your Dockerfile on any image, &lt;a href="https://hub.docker.com/_/php/"&gt;PHP&lt;/a&gt;, &lt;a href="https://hub.docker.com/_/node/"&gt;NodeJS&lt;/a&gt;, the &lt;a href="https://hub.docker.com/_/microsoft-dotnet-core-sdk/"&gt;.NET Core SDK&lt;/a&gt;, whatever tech stack you're building with.  Then build on it, add in whatever extra tools you need, maybe you want to add &lt;code&gt;git&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;A prebuilt environment containing everything you need, with exactly the versions you want. What more could you need?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lv6cZ70B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2019/08/ButWaitTheresMore.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lv6cZ70B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simonreynolds.ie/content/images/2019/08/ButWaitTheresMore.png" alt="Developing in a docker container"&gt;&lt;/a&gt;But wait...there's more!&lt;/p&gt;

&lt;p&gt;Why stop at specifying just your build environment? How about what VS Code settings or extensions are needed?&lt;/p&gt;

&lt;p&gt;Let's extend the &lt;code&gt;devcontainer.json&lt;/code&gt; with some extra instructions. We can say we want some extensions installed by default. If you use VS Code for F# then you probably already have the amazing &lt;a href="https://ionide.io/"&gt;Ionide&lt;/a&gt; plugin installed.&lt;/p&gt;

&lt;p&gt;But you want your project to be easy for newcomers to get up and running. Telling them to go install 5 different extensions just get started isn't the best way to start off a relationship with a potential new user or contributor.&lt;/p&gt;

&lt;p&gt;Let's just list the extensions we need instead...&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyAwesomeApp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dockerFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dockerfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"appPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ionide.ionide-fsharp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.csharp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"editorconfig.editorconfig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        
        &lt;/span&gt;&lt;span class="s2"&gt;"ionide.ionide-paket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ionide.ionide-fake"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What about VS Code settings? All settings in VS Code are specified in json files, so we just add one to the &lt;code&gt;.devcontainer&lt;/code&gt; folder and reference it in the Dockerfile.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"FSharp.fsacRuntime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"netcore"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is named &lt;code&gt;settings.vscode.json&lt;/code&gt; so we add it to our Dockerfile&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; fsharp:netcore&lt;/span&gt;

&lt;span class="c"&gt;# Copy endpoint specific user settings into container to specify&lt;/span&gt;
&lt;span class="c"&gt;# .NET Core should be used as the runtime.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; settings.vscode.json /root/.vscode-remote/data/Machine/settings.json&lt;/span&gt;

&lt;span class="c"&gt;# Install git, process tools&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;git procps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now when we open the project in VS Code we get a prompt to reopen it in a container. It will create a Docker container based on the supplied &lt;code&gt;DOCKERFILE&lt;/code&gt;, automatically open and forward port 8080 from the container to the host and install all the extensions listed. Now we can happily write our build script that assumes the presence of a build tool and make sure that making changes to it is a smoother experience because VS Code will even have the right extensions for it!&lt;/p&gt;

&lt;p&gt;The full reference for what &lt;code&gt;devcontainer.json&lt;/code&gt; can do is &lt;a href="https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference"&gt;here&lt;/a&gt;, and it can do a lot!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>netcore</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Creating a single file application in .NET Core</title>
      <dc:creator>Simon Reynolds</dc:creator>
      <pubDate>Thu, 18 Jul 2019 20:37:09 +0000</pubDate>
      <link>https://dev.to/simonreynolds/creating-a-single-file-application-in-net-core-5ab5</link>
      <guid>https://dev.to/simonreynolds/creating-a-single-file-application-in-net-core-5ab5</guid>
      <description>&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%2Fimages.unsplash.com%2Fphoto-1465920431246-94bf7d9d4269%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" 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%2Fimages.unsplash.com%2Fphoto-1465920431246-94bf7d9d4269%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Creating a single file application in .NET Core"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;.NET Core has long supported the idea of a self-contained application, where the build process results in a single executable application. Until the release of .NET Core 3 preview 6 though, the resulting output would be a single executable and every supporting library or dll that it needed.&lt;/p&gt;

&lt;p&gt;Let's examine the changes using a simple Hello World application...&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;SingleExe
dotnet new console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a simple console application with a &lt;code&gt;csproj&lt;/code&gt; like below&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;netcoreapp3.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&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;If we add a &lt;code&gt;RuntimeIdentifier&lt;/code&gt; for our environment we can then publish an application built for that environment that can be ran without requiring the .NET Core runtime to be installed. A breakdown of Runtime Identifiers can be found &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/rid-catalog" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once we add the appropriate identifier, e.g. &lt;code&gt;&amp;lt;RuntimeIdentifier&amp;gt;osx-x64&amp;lt;/RuntimeIdentifier&amp;gt;&lt;/code&gt; we can then publish the application using&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet publish -c Release&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will result in a lot of output!&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%2Fsimonreynolds.ie%2Fcontent%2Fimages%2F2019%2F07%2FScreen-Shot-2019-07-18-at-21.25.18.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%2Fsimonreynolds.ie%2Fcontent%2Fimages%2F2019%2F07%2FScreen-Shot-2019-07-18-at-21.25.18.png" alt="Creating a single file application in .NET Core"&gt;&lt;/a&gt;72MB across 191 items is not a small self-contained application!&lt;/p&gt;

&lt;p&gt;.NET Core 3 introduces a number of new options for consolidating all this output.&lt;/p&gt;

&lt;p&gt;If we update our &lt;code&gt;csproj&lt;/code&gt; to the following, then our output will be merged into a single executable and uncalled code will be trimmed from it&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;PublishTrimmed&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishTrimmed&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PublishSingleFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishSingleFile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fsimonreynolds.ie%2Fcontent%2Fimages%2F2019%2F07%2FScreen-Shot-2019-07-18-at-21.02.36.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%2Fsimonreynolds.ie%2Fcontent%2Fimages%2F2019%2F07%2FScreen-Shot-2019-07-18-at-21.02.36.png" alt="Creating a single file application in .NET Core"&gt;&lt;/a&gt;A single 30MB executable is a lot more manageable&lt;/p&gt;

&lt;p&gt;Now, 30MB for an application that in this case simply writes "Hello World" to a console screen may seem excessive but remember that this is including every part of .NET Core that the application needs to run, it has absolutely no external dependencies!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be careful here though, anything that uses reflection may be incorrectly trimmed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test your applications after trimming them! You can tell the trimmer to include specific namespaces, classes or methods using the &lt;code&gt;TrimmerRootAssembly&lt;/code&gt; element.&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;ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;TrimmerRootAssembly&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Namespace.To.Keep"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all still just using IL (Intermediate Language) though, the bytecode that .NET code compiles to and is JIT (Just In Time) compiled to the target machine's native code every time the application is ran.&lt;/p&gt;

&lt;p&gt;If we're going to build for a specific platform, or offer builds for multiple platforms then it would make sense to pre-compile as much of the code to native machine code as we can.&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;PublishReadyToRun&lt;/code&gt; option. We include it in our &lt;code&gt;csproj&lt;/code&gt; file so that the whole file now looks like this...&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;netcoreapp3.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishTrimmed&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishTrimmed&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishSingleFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishSingleFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishReadyToRun&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishReadyToRun&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Set the RuntimeIdentifier below to match your own system --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RuntimeIdentifier&amp;gt;&lt;/span&gt;osx-x64&lt;span class="nt"&gt;&amp;lt;/RuntimeIdentifier&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 the compiler will pre-compile as much code as it can to (in this case) Mac specific machine code. This will not have to be JITted each time the application runs, leading to a noticeably faster application start.&lt;/p&gt;

&lt;p&gt;The tradeoff here is that the resulting executables are now platform specific but if you can provide a pre-built executable for each of the major platforms then it could be well worth considering.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>netcore</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
