<?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: Cain Voong</title>
    <description>The latest articles on DEV Community by Cain Voong (@cainux).</description>
    <link>https://dev.to/cainux</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%2F522508%2F1d82caae-a7dd-46d9-b32e-f5b71794c2ff.jpeg</url>
      <title>DEV Community: Cain Voong</title>
      <link>https://dev.to/cainux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cainux"/>
    <language>en</language>
    <item>
      <title>Add AVDL Support to a .NET Project</title>
      <dc:creator>Cain Voong</dc:creator>
      <pubDate>Sun, 24 Jan 2021 19:56:28 +0000</pubDate>
      <link>https://dev.to/cainux/add-avdl-support-to-a-net-project-1hoo</link>
      <guid>https://dev.to/cainux/add-avdl-support-to-a-net-project-1hoo</guid>
      <description>&lt;p&gt;By now, we have a good grasp on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Taking Avro IDL files and generating C# classes&lt;/li&gt;
&lt;li&gt;Automating the above so we can do it on lots of files with ease&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this final step, I will create a C# project and configure it in a way so developers only need to add/modify &lt;code&gt;avdl&lt;/code&gt; files and &lt;em&gt;build&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create the Project
&lt;/h1&gt;

&lt;p&gt;We'll start from scratch, by creating the project and then adding an &lt;code&gt;Avro&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new classlib &lt;span class="nt"&gt;--name&lt;/span&gt; MyProject
&lt;span class="nb"&gt;cd &lt;/span&gt;MyProject
&lt;span class="nb"&gt;mkdir &lt;/span&gt;Avro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the package &lt;a href="https://www.nuget.org/packages/Confluent.SchemaRegistry.Serdes.Avro/"&gt;Confluent.SchemaRegistry.Serdes.Avro&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Confluent.SchemaRegistry.Serdes.Avro &lt;span class="nt"&gt;--version&lt;/span&gt; 1.5.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then copy the &lt;code&gt;AVDL&lt;/code&gt; folder and &lt;code&gt;Generate.ps1&lt;/code&gt; script from the &lt;a href="https://dev.to/cainux/automate-avdl-to-c-generation-1mk5"&gt;previous post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project should end up looking like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyProject
├── Avro
│   ├── AVDL
│   │   └── ExampleMessage.avdl
│   └── Generate.ps1
├── Class1.cs
└── MyProject.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Modify .csproj
&lt;/h1&gt;

&lt;p&gt;Before building the .NET project, we want MSBuild to generate our Avro classes. This can be done as a PreBuild step which is configured within &lt;code&gt;MyProject.csproj&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inform MSBuild
&lt;/h2&gt;

&lt;p&gt;Open the file then add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Target&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"PreBuild"&lt;/span&gt; &lt;span class="na"&gt;BeforeTargets=&lt;/span&gt;&lt;span class="s"&gt;"PreBuildEvent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Exec&lt;/span&gt; &lt;span class="na"&gt;WorkingDirectory=&lt;/span&gt;&lt;span class="s"&gt;"$(ProjectDir)Avro"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"pwsh -ExecutionPolicy RemoteSigned -File Generate.ps1"&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;span class="nt"&gt;&amp;lt;Compile&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"$(ProjectDir)Avro/_generated/**/*$(DefaultLanguageSourceExtension)"&lt;/span&gt; &lt;span class="na"&gt;Exclude=&lt;/span&gt;&lt;span class="s"&gt;"@(Compile)"&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;span class="nt"&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute the PowerShell script to generate Avro classes first&lt;/li&gt;
&lt;li&gt;Inform MSBuild of the new files, but also ensure not to include them twice if they already exist (see &lt;a href="https://stackoverflow.com/a/59738881/42200"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tweak for Visual Studio
&lt;/h2&gt;

&lt;p&gt;Also, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;EmbeddedResource&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Avro\AVDL\**\*.avdl"&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 a little hack to trick Visual Studio into marking the build as out of date if you make any changes in the AVDL folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build
&lt;/h2&gt;

&lt;p&gt;Now, we're ready to build:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Which results in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft (R) Build Engine version 16.7.0+7fb82e5b2 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /home/cainux/code/MyProject/MyProject.csproj (in 313 ms).
  Generating Avro classes...
  avro-tools not found, downloading from https://repo1.maven.org/maven2/org/apache/avro/avro-tools/1.10.0/avro-tools-1.10.0.jar to /home/cainux/.avro-tools/avro-tools-1.10.0.jar
  Running: /home/cainux/.dotnet/tools/avrogen -s ./_generated/avro/schema/ExampleMessage.avsc ./_generated/avro/classes
  MyProject -&amp;gt; /home/cainux/code/MyProject/bin/Debug/netstandard2.0/MyProject.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We went from manually generating C# classes from Avro IDL files to making it happen automagically withing a .NET project. Developers only need to put their AVDL files in the right place and run build to generate the classes. Now you can focus on building the rest of your application with one less thing to think about.&lt;/p&gt;

&lt;p&gt;If you're managing your code with source control (if not, why on earth not?!) such as Git - remember to ignore the &lt;code&gt;_generated&lt;/code&gt; folder and its contents as they are build assets and shouldn't be checked in to source control.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>avro</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Automate AVDL to C# Generation</title>
      <dc:creator>Cain Voong</dc:creator>
      <pubDate>Sun, 24 Jan 2021 19:56:05 +0000</pubDate>
      <link>https://dev.to/cainux/automate-avdl-to-c-generation-1mk5</link>
      <guid>https://dev.to/cainux/automate-avdl-to-c-generation-1mk5</guid>
      <description>&lt;p&gt;In the previous post, you saw how to take an Avro IDL file and manually turn that into a C# class.&lt;/p&gt;

&lt;p&gt;For a small number of files, this is fine but as soon as you start dealing with a lot of them it'll be something you'll want to automate. I've written a PowerShell script to do this will cover how to use it + what it does.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jdk.java.net/"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet-core"&gt;.NET Core SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Apache.Avro.Tools/1.10.0"&gt;Apache.Avro.Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1"&gt;PowerShell Core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Folder Structure
&lt;/h1&gt;

&lt;p&gt;Create a folder called &lt;code&gt;Avro&lt;/code&gt; and within that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a file called &lt;code&gt;Generate.ps1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a folder called &lt;code&gt;AVDL&lt;/code&gt; and place any &lt;code&gt;.avdl&lt;/code&gt; files in there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── Avro
    ├── AVDL
    │   └── ExampleMessage.avdl
    └── Generate.ps1        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  The Generate.ps1 Script
&lt;/h1&gt;

&lt;p&gt;The PowerShell script is what does all the work. The contents can be copied from this gist:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;
  
  
  What it does:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Downloads &lt;code&gt;avro-tools&lt;/code&gt; to &lt;code&gt;$HOME/.avro-tools&lt;/code&gt; if it's not there already&lt;/li&gt;
&lt;li&gt;Scan the contents of the AVDL folder&lt;/li&gt;
&lt;li&gt;For each &lt;code&gt;.avdl&lt;/code&gt; file found, generate the &lt;code&gt;.avsc&lt;/code&gt; and from that, the C# class&lt;/li&gt;
&lt;li&gt;All generated files are written to the &lt;code&gt;Avro/_generated&lt;/code&gt; folder&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Running
&lt;/h1&gt;

&lt;p&gt;To run the script just do:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The results should end up like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── Avro
    ├── AVDL
    │   └── ExampleMessage.avdl
    ├── Generate.ps1
    └── _generated
        └── avro
            ├── classes
            │   └── example
            │       └── avro
            │           └── ExampleMessage.cs
            └── schema
                └── ExampleMessage.avsc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script also does some basic change detection so it'll only generate the files if something has changed within the &lt;code&gt;AVDL&lt;/code&gt; folder. It's just a simple check of last modified dates, so it's not perfect (i.e. doesn't work with deletions) but it works for most cases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;We took the manual steps from the previous post and automated it using PowerShell. In the final post, we'll look at adding this to a project so it gets executed as part of the build process.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>avro</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Create C# Classes from Avro IDL</title>
      <dc:creator>Cain Voong</dc:creator>
      <pubDate>Sun, 24 Jan 2021 19:53:52 +0000</pubDate>
      <link>https://dev.to/cainux/create-c-classes-from-avro-idl-1f84</link>
      <guid>https://dev.to/cainux/create-c-classes-from-avro-idl-1f84</guid>
      <description>&lt;p&gt;I was recently involved in a project where we built a .NET service which consumed messages from various Kafka topics, the messages themselves were serialised using &lt;a href="https://avro.apache.org/"&gt;Apache Avro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the first time I had come across Avro, and there aren't many tools in the .NET ecosystem around this. In this series, I'll cover how to generate C# classes from Avro schemata, automate the steps, and finally how to integrate it with your project's build.&lt;/p&gt;

&lt;h1&gt;
  
  
  Avro Schema
&lt;/h1&gt;

&lt;p&gt;Avro schemata are defined as JSON in file with the extension &lt;code&gt;.avsc&lt;/code&gt;. An example schema of a message which contains a single string would be:&lt;br&gt;
&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;"type"&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;"record"&lt;/span&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="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;"ExampleMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"namespace"&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;"example.avro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fields"&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;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="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;"body"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;"string"&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;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;You can generate C# classes from &lt;code&gt;.avsc&lt;/code&gt; files using &lt;code&gt;avrogen&lt;/code&gt;, which comes as part of &lt;a href="https://www.nuget.org/packages/Apache.Avro.Tools/"&gt;https://www.nuget.org/packages/Apache.Avro.Tools/&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Avro IDL
&lt;/h1&gt;

&lt;p&gt;In our project, the messages were already defined and all we had to do was create the corresponding C# classes to hydrate into.&lt;/p&gt;

&lt;p&gt;There was an extra catch for us: the schemata themselves were defined using the higher-level &lt;a href="https://avro.apache.org/docs/current/idl.html"&gt;Avro IDL&lt;/a&gt; language and there currently isn't a tool to generate C# classes from Avro IDL.&lt;/p&gt;

&lt;p&gt;The Avro IDL version of above schema would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@namespace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"example.avro"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;ExampleMessage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ExampleMessage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Avro IDL to C# Class
&lt;/h1&gt;

&lt;p&gt;Avro IDL files have the extension &lt;code&gt;.avdl&lt;/code&gt;. To turn these files into C# classes we had to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turn AVDL into AVSC using &lt;a href="https://mirrors.ukfast.co.uk/sites/ftp.apache.org/avro/avro-1.10.0/java/avro-tools-1.10.0.jar"&gt;the Java tool avro-tools&lt;/a&gt; - this requires Java&lt;/li&gt;
&lt;li&gt;Turn AVSC into a C# class using the &lt;code&gt;avrogen&lt;/code&gt; tool mentioned earlier&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Take the example Avro IDL above and save it to a file called &lt;code&gt;ExampleMessage.avdl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Turn it into an &lt;code&gt;.avsc&lt;/code&gt; file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; /path/to/avro-tools-1.10.0.jar idl2schemata ExampleMessage.avdl &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces &lt;code&gt;ExampleMessage.avsc&lt;/code&gt;, which we then turn into a C# class with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;avrogen &lt;span class="nt"&gt;-s&lt;/span&gt; ExampleMessage.avsc &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final file created is &lt;code&gt;./example/avro/ExampleMessage.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;example.avro&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Avro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Avro.Specific&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;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleMessage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISpecificRecord&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="n"&gt;Schema&lt;/span&gt; &lt;span class="n"&gt;_SCHEMA&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Avro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{\"type\":\"record\",\"name\":\"ExampleMessage\",\"namespace\":\"example.avro\",\"fields\":[{\"n"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"ame\":\"body\",\"type\":\"string\"}]}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_body&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;virtual&lt;/span&gt; &lt;span class="n"&gt;Schema&lt;/span&gt; &lt;span class="n"&gt;Schema&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;return&lt;/span&gt; &lt;span class="n"&gt;ExampleMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;body&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;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_body&lt;/span&gt;&lt;span class="p"&gt;;&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="nf"&gt;Get&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;fieldPos&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;fieldPos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AvroRuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bad index "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fieldPos&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" in Get()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Put&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;fieldPos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;fieldValue&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;fieldPos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;fieldValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AvroRuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bad index "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fieldPos&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" in Put()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;While this works for a single file the experience doesn't really scale when we start dealing with multiple files.&lt;/p&gt;

&lt;p&gt;For Java developers, there are plugins which handle this so all developers need to do is add AVDL files to their projects and the tooling generates the Java classes.&lt;/p&gt;

&lt;p&gt;Ideally, we should have some equivalent in .NET, which is what I'll be covering in the rest of this series!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>avro</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Dockerising .NET Core &amp; Svelte</title>
      <dc:creator>Cain Voong</dc:creator>
      <pubDate>Sat, 23 Jan 2021 19:09:55 +0000</pubDate>
      <link>https://dev.to/cainux/net-core-svelte-and-docker-1bpm</link>
      <guid>https://dev.to/cainux/net-core-svelte-and-docker-1bpm</guid>
      <description>&lt;p&gt;The previous post covered how to set up a web application with a .NET Core backend and Svelte frontend.&lt;/p&gt;

&lt;p&gt;In this post we'll package it up into a single Docker image ready to be deployed somewhere.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Approach
&lt;/h1&gt;

&lt;p&gt;We'll be taking advantage of Docker's &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/" rel="noopener noreferrer"&gt;multi-stage builds&lt;/a&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build the frontend using Node&lt;/li&gt;
&lt;li&gt;then the backend using .NET Core SDK&lt;/li&gt;
&lt;li&gt;copy the results to an image containing only the ASP.NET Core runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Dockerfile
&lt;/h1&gt;

&lt;p&gt;Create a file named &lt;code&gt;Dockerfile&lt;/code&gt;. I usually do this with:&lt;br&gt;
&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;touch &lt;/span&gt;Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Frontend Build Stage
&lt;/h2&gt;

&lt;p&gt;We'll start the file off with the below snippet. I've added comments to describe each step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use Node.js 14, name this stage 'frontend'&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;frontend&lt;/span&gt;

&lt;span class="c"&gt;# Our working directory within the image&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="c"&gt;# Copy package and lock files then install dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .             &lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package-lock.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy the rest of the files for the frontend&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; rollup.config.js .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; svelte-app ./svelte-app&lt;/span&gt;

&lt;span class="c"&gt;# Build - this'll output files to /build/wwwroot&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If you're wondering "why copy the package and lock files first?": it's so Docker creates and caches an intermediate layer containing your dependencies (in node_modules). This gets reused in subsequent builds if those files remain unchanged and saves having to redownload dependencies on each build.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend Build Stage
&lt;/h2&gt;

&lt;p&gt;Now add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use .NET Core SDK, name this stage 'backend'&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:5.0-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="c"&gt;# Copy the csproj file then install dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; dotnet-svelte.csproj .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet restore dotnet-svelte.csproj

&lt;span class="c"&gt;# Copy everything else&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Publish, and output the results to /publish&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; /publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to the frontend stage, we copy the &lt;code&gt;csproj&lt;/code&gt; file first and restore dependencies to create an intermediate layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combine the Results
&lt;/h2&gt;

&lt;p&gt;We named our stages in the earlier snippets with &lt;code&gt;AS frontend&lt;/code&gt; and &lt;code&gt;AS backend&lt;/code&gt;. In our final stage we can reference the earlier stages and copy files from them. Add to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ASP.NET Core Runtime&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:5.0-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Where our application will live&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the build results of the frontend stage&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=frontend /build/wwwroot ./wwwroot&lt;/span&gt;

&lt;span class="c"&gt;# Copy the build results of the backend stage&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=backend /publish .&lt;/span&gt;

&lt;span class="c"&gt;# Run our web application on startup (will listen on port 80 by default)&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; /app/dotnet-svelte&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Final Dockerfile
&lt;/h1&gt;

&lt;p&gt;Should look like this (comments omitted):&lt;br&gt;
&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="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .             &lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package-lock.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; rollup.config.js .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; svelte-app ./svelte-app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:5.0-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; dotnet-svelte.csproj .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet restore dotnet-svelte.csproj
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; /publish

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:5.0-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=frontend /build/wwwroot ./wwwroot&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=backend /publish .&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; /app/dotnet-svelte&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Building &amp;amp; Running
&lt;/h1&gt;

&lt;p&gt;Builds an image from the Dockerfile, and name it &lt;code&gt;dotnet-svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; dotnet-svelte &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 5000:80 dotnet-svelte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; tells docker to automatically remove the container once stopped&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 5000:80&lt;/code&gt; maps your local port 5000 to the container's port 80&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, browse to &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; and once again you will see:&lt;/p&gt;

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

&lt;p&gt;Congratulations! You now have an image ready to be deployed somewhere.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;This post was really more about Docker and multi-stage builds than anything else. We:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used a Node image to build the Svelte application&lt;/li&gt;
&lt;li&gt;Used a .NET Core SDK image to build the ASP.NET application&lt;/li&gt;
&lt;li&gt;Copied the results of both to an ASP.NET runtime image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting image contains only the parts we need: static files for the frontend, binary files for the backend and the runtime required to run it.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>svelte</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>.NET Core and Svelte</title>
      <dc:creator>Cain Voong</dc:creator>
      <pubDate>Thu, 03 Dec 2020 09:03:45 +0000</pubDate>
      <link>https://dev.to/cainux/net-core-and-svelte-f8o</link>
      <guid>https://dev.to/cainux/net-core-and-svelte-f8o</guid>
      <description>&lt;p&gt;In this post I will show you how to set up a .NET Core application with a Svelte frontend for development.&lt;/p&gt;

&lt;h1&gt;
  
  
  Svelte
&lt;/h1&gt;

&lt;p&gt;You've probably heard of React, Vue and Angular by now. &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; is an alternative to those with some important differences which make it stand out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Traditional frameworks allow you to write declarative state-driven code, but there's a penalty: the browser must do extra work to convert those declarative structures into DOM operations, using techniques like &lt;a href="https://svelte.dev/blog/virtual-dom-is-pure-overhead" rel="noopener noreferrer"&gt;virtual DOM diffing&lt;/a&gt; that eat into your frame budget and tax the garbage collector.&lt;/p&gt;

&lt;p&gt;Instead, Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you're able to write ambitious applications with excellent performance characteristics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://svelte.dev/blog/svelte-3-rethinking-reactivity#What_is_Svelte" rel="noopener noreferrer"&gt;https://svelte.dev/blog/svelte-3-rethinking-reactivity#What_is_Svelte&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Personally, I like Svelte because I just find it so easy - &lt;em&gt;jQuery easy&lt;/em&gt; - to build applications with. If you already have a good grasp of JavaScript, HTML and CSS then there isn't much more to learn in order to get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Before you begin
&lt;/h1&gt;

&lt;p&gt;Have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet-core" rel="noopener noreferrer"&gt;.NET Core SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.JS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing, I'm running .NET Core 5.0.100 and Node.JS 14.15.1&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating
&lt;/h1&gt;

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

npx degit sveltejs/template dotnet-svelte


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

&lt;/div&gt;

&lt;p&gt;This creates a &lt;code&gt;dotnet-svelte&lt;/code&gt; directory then places the Svelte starter template in there. Next thing to do is spin up a .NET Core Web Application within that folder:&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;cd &lt;/span&gt;dotnet-svelte
dotnet new web


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Configuration
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Rename Directories
&lt;/h2&gt;

&lt;p&gt;This makes things a bit more in line with .NET conventions.&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;# Rename 'src' to 'svelte-app'&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;src svelte-app

&lt;span class="c"&gt;# Rename 'public' to 'wwwroot'&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;public wwwroot


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;rollup.config.js&lt;/code&gt;:
&lt;/h2&gt;

&lt;p&gt;The Svelte starter template uses &lt;code&gt;sirv&lt;/code&gt; during development to serve static files. We can switch to using our .NET application by applying the modifications below.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;function serve()&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;To&lt;/p&gt;

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

&lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;watch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;export default&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte-app/main.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- we renamed src to svelte-app&lt;/span&gt;
&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;iife&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wwwroot/build/bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- renamed public to wwwroot&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;A little further down, also update the directory livereload watches:&lt;/p&gt;

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

&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;livereload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wwwroot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;Startup.cs&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;On the .NET side we can tell it to serve the static content which Svelte generates.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Configure&lt;/code&gt; method:&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;// Add these before app.UseRouting();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseDefaultFiles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseStaticFiles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Running
&lt;/h1&gt;

&lt;p&gt;Now we're ready!&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev


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

&lt;/div&gt;

&lt;p&gt;Open your browser at &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; and you should be greeted with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxh38glfcl8lh8za52im9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxh38glfcl8lh8za52im9.png" alt="Hello World!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Development
&lt;/h1&gt;

&lt;p&gt;If you modify any of the frontend files they'll get automatically rebuilt and refreshed in the browser. Backend changes are also automatically rebuilt but you'll have to manually refresh.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;We took the Svelte starter template, tweaked it a little to fit with some .NET Core defaults then quickly set up a .NET Core service to serve the static files built by Svelte.&lt;/p&gt;

&lt;p&gt;From here you can start building out your application.&lt;/p&gt;

&lt;p&gt;At some point, you will need to deploy this somewhere which will require building both applications separately then combining the results. I'll cover that in a separate post.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>svelte</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
