<?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: Bazen</title>
    <description>The latest articles on DEV Community by Bazen (@bazen).</description>
    <link>https://dev.to/bazen</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%2F474458%2Fcd50de06-fb56-4a11-92f6-036b18bfd4d0.png</url>
      <title>DEV Community: Bazen</title>
      <link>https://dev.to/bazen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bazen"/>
    <language>en</language>
    <item>
      <title>The Memphis .NET SDK: My Journey from Contributor to Maintainer</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Sat, 20 May 2023 06:06:56 +0000</pubDate>
      <link>https://dev.to/bazen/the-memphis-net-sdk-my-journey-from-contributor-to-maintainer-5ha</link>
      <guid>https://dev.to/bazen/the-memphis-net-sdk-my-journey-from-contributor-to-maintainer-5ha</guid>
      <description>&lt;p&gt;Hello! My name is Bazen, and I'm a software engineer who enjoys working on exciting projects and, of course, coffee. One of my favorite frameworks is .NET and the C# programming language. I want to share my journey from contributing to maintaining the .NET SDK for Memphis. Memphis is an open-source project, and in this article, I will start by explaining what Memphis is, my contribution journey, and, last but not least, the different ways others can contribute to Memphis and other open-source projects.&lt;/p&gt;

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

&lt;p&gt;Memphis is a next-generation message broker. It is a simple, robust, and durable cloud-native message broker. It provides cost-effective, fast, and reliable development of modern queue-based systems. Memphis scales exceptionally well with large volumes of streamed and enriched data. It is designed with development experience in mind and requires significantly less development time for data-oriented developers and data engineers than other solutions. Memphis is transparent and provides visibility on the activities taking place, which is helpful when troubleshooting. Memphis is feature rich and contains several features not mentioned here. I recommend checking it out on &lt;a href="https://github.com/memphisdev/memphis"&gt;GitHub&lt;/a&gt; and The official &lt;a href="https://memphis.dev/"&gt;Memphis&lt;/a&gt; website to learn more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Contribution
&lt;/h2&gt;

&lt;p&gt;I was working on a company project involving working with high-volume data. I was researching different event streaming platforms such as Kafka, RabbitMq, Amazon SQS, and more to find a suitable solution, and that is how I stumbled across Memphis. At first glance, I was impressed by the observability of the platform, which motivated me to set it up locally and try it out. I played around with the Go SDK and quite liked the platform, which inspired me to learn more about it on &lt;a href="https://github.com/memphisdev/memphis"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the time, Memphis already had SDKs in multiple languages, such as Go, TypeScript, and Python. However, the &lt;a href="https://github.com/memphisdev/memphis.net"&gt;Memphis .NET SDK&lt;/a&gt; was in an early stage. Recognizing the platform's potential, I took it upon myself to reach out to the Memphis team and asked how I could contribute to the .NET SDK. Not long after that, I received a response from &lt;a href="https://www.linkedin.com/in/ybenhemo/"&gt;Yaniv Ben Hemo&lt;/a&gt;, the Co-Founder and CEO at Memphis. He was very welcoming and pointed me to the issues I could work on.&lt;/p&gt;

&lt;p&gt;I worked on one of the issues and made my first pull request to the Memphis .NET SDK, and I was pleased by the encouraging feedback from the Memphis community.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pNUTaw5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq9qrplp02g4qdnqjo5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pNUTaw5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq9qrplp02g4qdnqjo5h.png" alt="Image description" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since then, I have contributed actively to the .NET SDK of the Memphis project. In addition, I am an active participant in the community, helping to resolve issues, guiding new contributors, and ensuring that the .NET SDK for Memphis remains up-to-date and fully functional.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;As a Software Engineer, contributing to open-source projects and building in public is very important, and it provides the opportunity to learn about a new subject in detail. For example, my understanding of message brokers and their technical complexity was limited before Memphis. Some interesting things I learned from Memphis are schema verse and dead letter station.&lt;/p&gt;

&lt;p&gt;Schema verse is a schema store and schema management layer on top of the Memphis broker. It's a neat way to specify and enforce the data structure, and this is useful to validate input data and increase its quality. The schema can be defined from the Memphis UI and using code, and one schema can be applied to multiple stations. The supported formats are ProtoBuf, Avro, JSON, and GraphQL. You can learn more about schema verse at &lt;a href="https://docs.memphis.dev/memphis/memphis/schemaverse-schema-management"&gt;Memphis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The other concept is the dead letter station(DLS), which is where faulty messages end up. A message can be considered faulty for many reasons, for example, if it doesn’t satisfy the enforced schema, if a consumer fails to process it properly, and so on. In these scenarios, instead of dropping these messages, Memphis stores them in the dead letter station(DLS) along with a log that explains why the message is in DLS. This is helpful when troubleshooting and increases the application’s resilience. You can learn more about DLS at &lt;a href="https://docs.memphis.dev/memphis/memphis/key-concepts/dead-letter"&gt;Memphis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Memphis has many features that make a developer's life easier and an exciting project to learn from and contribute to.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Contribute?
&lt;/h2&gt;

&lt;p&gt;A good starting point for anyone who would like to contribute is to&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out the different Memphis repositories and look for issues labeled “good first issue.” &lt;/li&gt;
&lt;li&gt;You can then apply the proposed changes &lt;/li&gt;
&lt;li&gt;Create the pull request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These pull requisites are likely to comprise small changes, and it is unlikely for there to be multiple back and forth; at the same time, this will give you a good feel of the contribution workflow. To learn more about the contribution guide, please check out the &lt;a href="https://docs.memphis.dev/memphis/getting-started/how-to-contribute"&gt;How to Contribute?&lt;/a&gt; guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memphis Community
&lt;/h2&gt;

&lt;p&gt;The Memphis Community is composed of very kind and skillful people. In addition to GitHub, they are very active on social media platforms such as &lt;a href="https://www.linkedin.com/company/memphis-dev/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://memphis.dev/discord"&gt;Discord&lt;/a&gt;, and &lt;a href="https://twitter.com/Memphis_Dev"&gt;Twitter&lt;/a&gt;. Since day-1, people like &lt;a href="https://www.linkedin.com/in/ybenhemo/"&gt;Yaniv Ben Hemo&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/idan-asulin/"&gt;Idan Asulin&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/avital-trifsik/"&gt;Avital Trifsik&lt;/a&gt; have been very welcoming and understanding. They were kind enough to send me their cool swag pack as a token of their appreciation. Moreover, they helped me understand and learn different technical aspects of the event processing platform. At first, the thought of contributing could seem daunting, but speaking from experience, I assure you that you will be relieved of your worries with a community like Memphis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Memphis owes much of its success to the tireless efforts of its contributors, and I am proud to be a part of this very knowledgeable and vibrant community of developers. I have been privileged to make valuable contributions to this next-generation event-processing platform. As Memphis continues to grow and evolve, there is no doubt that I will continue to contribute to the project. So, if you're a developer looking to get involved in a dynamic and exciting project, please join the Memphis community and contribute to help shape the future of event processing.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>dotnet</category>
      <category>memphis</category>
    </item>
    <item>
      <title>Using npm Workspaces With ReactJS and .NET</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Fri, 07 Jan 2022 16:41:40 +0000</pubDate>
      <link>https://dev.to/bazen/using-npm-workspaces-with-reactjstypescript-and-net-10me</link>
      <guid>https://dev.to/bazen/using-npm-workspaces-with-reactjstypescript-and-net-10me</guid>
      <description>&lt;p&gt;This article explains how to leverage the existing .NET SPA template to work with &lt;a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces" rel="noopener noreferrer"&gt;npm workspaces&lt;/a&gt;. explanation on what npm workspaces are is not addressed in this article. for any one who is new to npm workspaces its recommended to check &lt;a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces" rel="noopener noreferrer"&gt;npm official documentation&lt;/a&gt;. npm workspaces is a nice way of organizing code but at the time being in order to use workspaces in .NET some customization are required, which will be explained in the following sections of this article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Content
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="//#creating-.net-project"&gt;Creating .NET project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Setting up SPA&lt;/li&gt;
&lt;li&gt;&lt;a href="//#modifying-.net-project"&gt;Modifying .NET Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Configuring Publish Profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Creating .NET project
&lt;/h4&gt;

&lt;p&gt;.NET project with react can be created by running the following command&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 react &lt;span class="nt"&gt;-n&lt;/span&gt; SampleApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setting up SPA
&lt;/h4&gt;

&lt;p&gt;Once the &lt;code&gt;SampleApp&lt;/code&gt; project is created by default it will contain &lt;code&gt;ClientApp&lt;/code&gt; directory, which is where the SPA(in this case React App) resides. as the default SPA template doesn't fit the required scenario delete everything inside &lt;code&gt;ClientApp&lt;/code&gt; directory. &lt;/p&gt;

&lt;p&gt;To setup workspaces open terminal inside the &lt;code&gt;ClientApp&lt;/code&gt; directory first run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this command will generate &lt;code&gt;package.json&lt;/code&gt; file which will contain the workspace information. for this example I want to create four workspaces named&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@clientapp/table : contains React app that displays information in tabular format &lt;/li&gt;
&lt;li&gt;@clientapp/card : contains React app that displays information in card&lt;/li&gt;
&lt;li&gt;@clientapp/config : contains shared configurations(eg. tsconfig) &lt;/li&gt;
&lt;li&gt;@clientapp/core : contains shared components and functionalities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;ClientApp&lt;/code&gt; will now look like the following&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yph6pw4izp7kxi282p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yph6pw4izp7kxi282p6.png" alt="ClientApp folder structure" width="225" height="184"&gt;&lt;/a&gt;&lt;br&gt;
Now &lt;code&gt;package.json&lt;/code&gt; inside &lt;code&gt;ClientApp&lt;/code&gt; have to be updated to configure the workspaces as shown bellow:&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;"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;"@clientapp/root"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"start:table"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run start -w @clientapp/table"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start:card"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run start -w @clientapp/card"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:table"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build -w @clientapp/table"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:card"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build -w @clientapp/card"&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;"workspaces"&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;"workspaces/*/**"&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;To create the two applications inside &lt;code&gt;ClientApp\workspaces\apps&lt;/code&gt; directory run the following commands consecutively&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;@clientapp/table
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app table &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;updated &lt;code&gt;name&lt;/code&gt; field inside &lt;code&gt;ClientApp\workspaces\apps\table\package.json&lt;/code&gt; to&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="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"@clientapp/table"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;@clientapp/card
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app card &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;updated &lt;code&gt;name&lt;/code&gt; field inside &lt;code&gt;ClientApp\workspaces\apps\card\package.json&lt;/code&gt; to&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="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"@clientapp/card"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  changes for both apps
&lt;/h4&gt;

&lt;p&gt;By default in both &lt;code&gt;@clientapp/table&lt;/code&gt; &amp;amp; &lt;code&gt;@clientapp/card&lt;/code&gt; we will not be able to use the typescript libraries from other workspaces. in order to support typescript I will use &lt;code&gt;craco&lt;/code&gt; instead of &lt;code&gt;react-scripts&lt;/code&gt;. the changes in this section must be applied in both &lt;code&gt;@clientapp/table&lt;/code&gt; &amp;amp; &lt;code&gt;@clientapp/card&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;craco&lt;/code&gt; as dev dependency&lt;br&gt;
&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;craco &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create file name &lt;code&gt;craco.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&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="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getLoader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loaderByName&lt;/span&gt; &lt;span class="p"&gt;}&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="s2"&gt;craco&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * add the typescript workspaces this project is dependent up on
 */&lt;/span&gt;
&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../libs/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webpackConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/**
       * Overriding the output directory of build to fit with default configuration of .NET wrapper
       */&lt;/span&gt;
      &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appBuild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;webpackConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webpackConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;loaderByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;isFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;webpackConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the &lt;code&gt;scrpts&lt;/code&gt; section inside &lt;code&gt;package.json&lt;/code&gt; of both &lt;code&gt;@clientapp/table&lt;/code&gt; &amp;amp; &lt;code&gt;@clientapp/card&lt;/code&gt; as shown below:&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"craco start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"craco build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"craco test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"craco eject"&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="err"&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;ol&gt;
&lt;li&gt;@clientapp/core&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From &lt;code&gt;ClientApp\workspaces\libs&lt;/code&gt; open terminal and run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app core &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;updated &lt;code&gt;name&lt;/code&gt; field inside &lt;code&gt;ClientApp\workspaces\apps\card\package.json&lt;/code&gt; to&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="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"@clientapp/core"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since @clientapp/core is not dependent on another workspace there is no need to configure &lt;code&gt;craco&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From all application delete &lt;code&gt;node_modules&lt;/code&gt; directory &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To install the &lt;code&gt;@clientapp/core&lt;/code&gt; workspace into &lt;code&gt;@clientapp/table&lt;/code&gt; &amp;amp; &lt;code&gt;@clientapp/card&lt;/code&gt; run the following commands from &lt;code&gt;ClientApp&lt;/code&gt; directory&lt;br&gt;
&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; @clientapp/core &lt;span class="nt"&gt;-w&lt;/span&gt; @clientapp/table  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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; @clientapp/core &lt;span class="nt"&gt;-w&lt;/span&gt; @clientapp/card  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install the dependency packages run &lt;code&gt;npm install&lt;/code&gt; from &lt;code&gt;ClientApp&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;At this point the SPA workspace configuration is completed &amp;amp; can be tested by running either of the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start:table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start:card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Modifying .NET Project
&lt;/h4&gt;

&lt;p&gt;For development update &lt;code&gt;Configure&lt;/code&gt; method inside &lt;code&gt;Startup.cs&lt;/code&gt; by replacing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;spa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseReactDevelopmentServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;npmScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;spa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseReactDevelopmentServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;npmScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"run start:table"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start @clientapp/table. &amp;amp; replace it by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;spa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseReactDevelopmentServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;npmScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"run start:card"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start @clientapp/card&lt;/p&gt;

&lt;p&gt;For publish update &lt;code&gt;SampleApp.csproj&lt;/code&gt; by replacing&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;"PublishRunWebpack"&lt;/span&gt; &lt;span class="na"&gt;AfterTargets=&lt;/span&gt;&lt;span class="s"&gt;"ComputeFilesToPublish"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- As part of publishing, ensure the JS resources are freshly built in production mode --&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;"$(SpaRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"npm install"&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;"$(SpaRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"npm run build"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Include the newly-built files in the publish output --&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;DistFiles&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"$(SpaRoot)build\**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ResolvedFileToPublish&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"@(DistFiles-&amp;gt;'%(FullPath)')"&lt;/span&gt; &lt;span class="na"&gt;Exclude=&lt;/span&gt;&lt;span class="s"&gt;"@(ResolvedFileToPublish)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;RelativePath&amp;gt;&lt;/span&gt;%(DistFiles.Identity)&lt;span class="nt"&gt;&amp;lt;/RelativePath&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToPublishDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToPublishDirectory&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ExcludeFromSingleFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/ExcludeFromSingleFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ResolvedFileToPublish&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;By&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;"PublishRunWebpack"&lt;/span&gt; &lt;span class="na"&gt;AfterTargets=&lt;/span&gt;&lt;span class="s"&gt;"ComputeFilesToPublish"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Error&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"'$(SpaBuildScript)' == ''"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Spa build script is not specified."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- As part of publishing, ensure the JS resources are freshly built in production mode --&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;"$(SpaRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"npm install"&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;"$(SpaRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"$(SpaBuildScript)"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Include the newly-built files in the publish output --&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;DistFiles&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"$(SpaRoot)build\**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ResolvedFileToPublish&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"@(DistFiles-&amp;gt;'%(FullPath)')"&lt;/span&gt; &lt;span class="na"&gt;Exclude=&lt;/span&gt;&lt;span class="s"&gt;"@(ResolvedFileToPublish)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;RelativePath&amp;gt;&lt;/span&gt;%(DistFiles.Identity)&lt;span class="nt"&gt;&amp;lt;/RelativePath&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToPublishDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToPublishDirectory&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ExcludeFromSingleFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/ExcludeFromSingleFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ResolvedFileToPublish&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;Add Two publish profiles one for @clientapp/card &amp;amp; one for @clientapp/table&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CardAppProfile.pubxml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;ToolsVersion=&lt;/span&gt;&lt;span class="s"&gt;"4.0"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/developer/msbuild/2003"&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;DeleteExistingFiles&amp;gt;&lt;/span&gt;False&lt;span class="nt"&gt;&amp;lt;/DeleteExistingFiles&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ExcludeApp_Data&amp;gt;&lt;/span&gt;False&lt;span class="nt"&gt;&amp;lt;/ExcludeApp_Data&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LaunchSiteAfterPublish&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/LaunchSiteAfterPublish&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LastUsedBuildConfiguration&amp;gt;&lt;/span&gt;Release&lt;span class="nt"&gt;&amp;lt;/LastUsedBuildConfiguration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LastUsedPlatform&amp;gt;&lt;/span&gt;Any CPU&lt;span class="nt"&gt;&amp;lt;/LastUsedPlatform&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishProvider&amp;gt;&lt;/span&gt;FileSystem&lt;span class="nt"&gt;&amp;lt;/PublishProvider&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishUrl&amp;gt;&lt;/span&gt;bin\Release\net5.0\publish\&lt;span class="nt"&gt;&amp;lt;/PublishUrl&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;WebPublishMethod&amp;gt;&lt;/span&gt;FileSystem&lt;span class="nt"&gt;&amp;lt;/WebPublishMethod&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;SpaBuildScript&amp;gt;&lt;/span&gt;npm run build:card&lt;span class="nt"&gt;&amp;lt;/SpaBuildScript&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TableAppProfile.pubxml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;ToolsVersion=&lt;/span&gt;&lt;span class="s"&gt;"4.0"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/developer/msbuild/2003"&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;DeleteExistingFiles&amp;gt;&lt;/span&gt;False&lt;span class="nt"&gt;&amp;lt;/DeleteExistingFiles&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ExcludeApp_Data&amp;gt;&lt;/span&gt;False&lt;span class="nt"&gt;&amp;lt;/ExcludeApp_Data&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LaunchSiteAfterPublish&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/LaunchSiteAfterPublish&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LastUsedBuildConfiguration&amp;gt;&lt;/span&gt;Release&lt;span class="nt"&gt;&amp;lt;/LastUsedBuildConfiguration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LastUsedPlatform&amp;gt;&lt;/span&gt;Any CPU&lt;span class="nt"&gt;&amp;lt;/LastUsedPlatform&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishProvider&amp;gt;&lt;/span&gt;FileSystem&lt;span class="nt"&gt;&amp;lt;/PublishProvider&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PublishUrl&amp;gt;&lt;/span&gt;bin\Release\net5.0\publish\&lt;span class="nt"&gt;&amp;lt;/PublishUrl&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;WebPublishMethod&amp;gt;&lt;/span&gt;FileSystem&lt;span class="nt"&gt;&amp;lt;/WebPublishMethod&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;SpaBuildScript&amp;gt;&lt;/span&gt;npm run build:table&lt;span class="nt"&gt;&amp;lt;/SpaBuildScript&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;After adding these publish profiles, @cilentapp/table can be published by running the following command for&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet pubilsh /p:PublishProfile&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Properties&lt;/span&gt;&lt;span class="se"&gt;\P&lt;/span&gt;&lt;span class="s2"&gt;ublishProfiles&lt;/span&gt;&lt;span class="se"&gt;\T&lt;/span&gt;&lt;span class="s2"&gt;ableAppProfile.pubxml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for @cilentapp/card&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet pubilsh /p:PublishProfile&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Properties&lt;/span&gt;&lt;span class="se"&gt;\P&lt;/span&gt;&lt;span class="s2"&gt;ublishProfiles&lt;/span&gt;&lt;span class="se"&gt;\C&lt;/span&gt;&lt;span class="s2"&gt;ardAppProfile.pubxml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is one way of using npm workspaces with .NET, full source code can be found on &lt;a href="https://github.com/bazen-teklehaymanot/dotnet-npm-workspace-sample" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading, Happy coding! &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Understanding Docker, Docker Compose &amp; Swarm</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Tue, 22 Jun 2021 11:39:57 +0000</pubDate>
      <link>https://dev.to/bazen/understanding-docker-docker-compose-swarm-i31</link>
      <guid>https://dev.to/bazen/understanding-docker-docker-compose-swarm-i31</guid>
      <description>&lt;p&gt;The intention behind this article is to provide high level understanding of what they are, how to use them and explain the commonly used syntax &amp;amp; semantics. the article might be a bit long but the reason I preferred not make it into series is because there is no deep dive into each and every aspect of container solution.&lt;/p&gt;

&lt;p&gt;Points of discussion in this article&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Docker

&lt;ul&gt;
&lt;li&gt;Docker CLI&lt;/li&gt;
&lt;li&gt;
Container

&lt;ul&gt;
&lt;li&gt;Interacting with containers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Image

&lt;ul&gt;
&lt;li&gt;Creating an Image&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Persistent data

&lt;ul&gt;
&lt;li&gt;Bind Mount&lt;/li&gt;
&lt;li&gt;Volumes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Network&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;Swarm&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If particular section is not area of your interest feel free to jump between sections. having said that lets get to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Docker
&lt;/h3&gt;

&lt;p&gt;Docker at its core is a platform used to run and deploy applications in container, in addition to this docker also comprises a lot of features which you will come to see as we go further. The reason for running applications in a container is to facilitates the entire life cycle of software development and management(which includes development, testing, deployment, update &amp;amp; maintenance), which docker does in a very elegant way.&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker CLI
&lt;/h4&gt;

&lt;p&gt;The commands used in this article are from Windows machine &amp;amp; if you are using Mac/Linux the commands might be different(you might need to run the commands as &lt;code&gt;sudo&lt;/code&gt;).Initially the docker CLI commands were structured as following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker [OPTIONS] COMMAND
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as the product become bigger and bigger they also introduced &lt;code&gt;Management commands&lt;/code&gt; to make the CLI more organized. The command structure for &lt;code&gt;Management commands&lt;/code&gt; is as following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker [MANAGEMENT COMMAND] [SUB COMMAND] [SUB COMMAND OPTIONS]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For every command there is &lt;code&gt;--help&lt;/code&gt; option which provides all the necessary information's about the command and its corresponding options.  &lt;/p&gt;

&lt;p&gt;Example-1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container --help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will have the following output.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun15yczfnt8wtxncfvsj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun15yczfnt8wtxncfvsj.png" alt="Alt Example Sceenshot"&gt;&lt;/a&gt;&lt;br&gt;
The &lt;code&gt;--help&lt;/code&gt; command is quite useful because with the extensive feature sets of docker it can be difficult to memorize all the commands.&lt;/p&gt;
&lt;h4&gt;
  
  
  Container
&lt;/h4&gt;

&lt;p&gt;Are running instances of docker image &amp;amp; it is possible to run multiple container from the same docker image. Images are explained in the Image section for now lets take a look at a simple container command.&lt;/p&gt;

&lt;p&gt;Example-2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker container run --name nginx-server --publish 80:80 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or alternatively&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker container run --name nginx-server --publish 80:80 --detach nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this command if there is an existing image of nginx docker will run a container from that image however if there is no image of nginx docker will pull the image first and then start the container. lets take a look at the command&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;container&lt;/strong&gt; : &lt;code&gt;Management command&lt;/code&gt; used to execute all container related commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;--name&lt;/strong&gt; : sets the name of the container. &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;It is not possible for multiple containers to have the same name because the container name will be used for DNS resolution(which is explained in detail in the Network section ).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;--publish&lt;/strong&gt; : Maps the containers running port into host port. in this case we check this by visiting &lt;code&gt;http://localhost:80&lt;/code&gt; from browser. The port mapping pattern is as following
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;... --publish [HOST PORT]:[CONTAINER PORT] ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;It is not possible to use the same host port to run multiple containers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;--detach&lt;/strong&gt; : starts the container in background and prints only the container id&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nginx&lt;/strong&gt; : name of an image from which we want to run our container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another example&lt;/p&gt;

&lt;p&gt;Example-3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --name db-server --env MYSQL_ROOT_PASSWORD=my-sample-password --detach mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some images require environment variable to run(such as database server) and the &lt;code&gt;--env&lt;/code&gt; option is used to pass environment variable from CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other common container commands&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;docker container ls&lt;/code&gt; : lists all running containers&lt;br&gt;
&lt;code&gt;docker container ls -a&lt;/code&gt; : lists all containers that are running and that are not&lt;br&gt;
 &lt;code&gt;docker container stop nginx-server&lt;/code&gt; : stops the container named &lt;code&gt;nginx-server&lt;/code&gt;&lt;br&gt;
 &lt;code&gt;docker container start nginx-server&lt;/code&gt; : starts the container named &lt;code&gt;nginx-server&lt;/code&gt;&lt;br&gt;
&lt;code&gt;docker container logs nginx-server&lt;/code&gt; : prints the logs from running container named &lt;code&gt;nginx-server&lt;/code&gt;&lt;br&gt;
&lt;code&gt;docker container rm nginx-server&lt;/code&gt; : removes container named &lt;code&gt;nginx-server&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see above the commands are self explanatory and strait forward. The intention of showing those basic commands is to demonstrate &amp;amp; be familiar with the commands and usages. There is no need to memorize any of this as you can get those and many more sub-commands of the &lt;code&gt;container&lt;/code&gt; command which are not listed above by simply using the &lt;code&gt;--help&lt;/code&gt; command. &lt;/p&gt;

&lt;h5&gt;
  
  
  Interacting with containers
&lt;/h5&gt;

&lt;p&gt;There are two commands we can use to interact with containers.&lt;/p&gt;

&lt;h6&gt;
  
  
  1. Using &lt;code&gt;run&lt;/code&gt; command
&lt;/h6&gt;

&lt;p&gt;When starting a container using the &lt;code&gt;run&lt;/code&gt; command it is possible to add &lt;code&gt;-it&lt;/code&gt; option and have the container start in interactive mode. &lt;/p&gt;

&lt;p&gt;Example-4&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run -it --name nginx-server-it --publish 8080:80 nginx bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will give us the &lt;code&gt;bash&lt;/code&gt; console inside the &lt;code&gt;nginx-server-it&lt;/code&gt; container to interact with. The output is shown below &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdynotlfy3mqfhmmh7ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdynotlfy3mqfhmmh7ow.png" alt="Alt Interactive"&gt;&lt;/a&gt; &lt;br&gt;
With this method once we exit from the interactive window (in this case &lt;code&gt;bash&lt;/code&gt; terminal) the container will be stopped automatically.&lt;/p&gt;
&lt;h6&gt;
  
  
  2. Using &lt;code&gt;exec&lt;/code&gt; command
&lt;/h6&gt;

&lt;p&gt;&lt;code&gt;exec&lt;/code&gt; command is used to interact with running container.&lt;/p&gt;
&lt;h6&gt;
  
  
  Example-5
&lt;/h6&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container exec -it nginx-server-it bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command will have the same result to the previous(&lt;code&gt;... run -it&lt;/code&gt;) command. the difference is once we exit from the interactive window the container will keep running. &lt;/p&gt;
&lt;h4&gt;
  
  
  Image
&lt;/h4&gt;

&lt;p&gt;Are simply the binaries, libraries and source code that make up the application. and images are used as a template to construct a container. images are constructed in a layered fashion and &lt;strong&gt;Union file system&lt;/strong&gt; is used under the hood to achieve this. &lt;strong&gt;Union file system&lt;/strong&gt; is not covered in this article but for those of you who wants to know more about it &lt;a href="https://itnext.io/deep-dive-into-docker-internals-union-filesystem-5a1fbcd426b5" rel="noopener noreferrer"&gt;Deep Dive into Docker Internals — Union Filesystem&lt;/a&gt; is good article. the reason for creating images in layered fashion is mainly to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Speedup the startup time&lt;/li&gt;
&lt;li&gt;Avoid storing duplicate files&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;
  
  
  Creating an Image
&lt;/h5&gt;

&lt;p&gt;Images can be created either from an existing image or from &lt;code&gt;Dockerfile&lt;/code&gt;. lets take a look at each method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating image from existing image
The &lt;code&gt;tag&lt;/code&gt; command can be used to create from another image as shown below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example-6&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker image tag nginx sample/my-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look like &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfwm7p4syighr1k62i91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfwm7p4syighr1k62i91.png" alt="Alt Custom Image From Another"&gt;&lt;/a&gt;&lt;br&gt;
Though there is newly created image the &lt;code&gt;Id&lt;/code&gt; attribute for both images is the same. That's because the layers used to construct both images are identical therefor the layers are shared between the two images(This has to do with the &lt;strong&gt;Union file system&lt;/strong&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating image from Dockerfile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dockerfile comprises all the commands that user can use from the CLI. here are quick overview of the commands and description&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;FROM&lt;/code&gt; : sets the base image for subsequent instruction&lt;br&gt;&lt;br&gt;
&lt;code&gt;WORKDIR&lt;/code&gt; : Defines the working directory of the image&lt;br&gt;
&lt;code&gt;ENV&lt;/code&gt; : Environment variables expected to start a container similar to the &lt;code&gt;mysql&lt;/code&gt; example above.&lt;br&gt;
&lt;code&gt;RUN&lt;/code&gt; : To run commands inside the container&lt;br&gt;
&lt;code&gt;COPY&lt;/code&gt; : Copies files from source to target directory&lt;br&gt;
&lt;code&gt;EXPOSE&lt;/code&gt; : Exposed container port. This port can then be mapped to the host port using the &lt;code&gt;--publish&lt;/code&gt; command as shown in the example above. &lt;br&gt;
&lt;code&gt;CMD&lt;/code&gt; : Final command that runs when starting container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are the most commonly used commands, for extensive list of all available commands &lt;a href="https://docs.docker.com/engine/reference/builder/#from" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; is a great place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;It is recommended to put the commands for frequently changing items(such as source code) at the bottom and commands for items that doesn't change as often at the top.as the order of command entries define the way the image is constructed.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In every &lt;code&gt;Dockerfile&lt;/code&gt; there must be &lt;code&gt;FROM&lt;/code&gt; &amp;amp; &lt;code&gt;CMD&lt;/code&gt; commands. and to clarify if there is no &lt;code&gt;CMD&lt;/code&gt; command in a &lt;code&gt;Dockerfile&lt;/code&gt; that means &lt;code&gt;CMD&lt;/code&gt; is defined in the base image &amp;amp; it is inherited via the &lt;code&gt;FROM&lt;/code&gt; command.&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
  
  
  Example-7
&lt;/h5&gt;

&lt;p&gt;create file named &lt;code&gt;Dockerfile&lt;/code&gt; with  the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM nginx
WORKDIR /usr/share/nginx/html
COPY . .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create &lt;code&gt;index.html&lt;/code&gt; file with the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Docker is awsome!&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from the root directory run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker image build --tag sample/my-nginx-2 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! you created your own image which you can check by running the &lt;code&gt;ls&lt;/code&gt; command. to make things more interesting lets run the image created and see the the changes made.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker container run --rm -p 80:80 sample/my-nginx-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When visiting &lt;a href="http://localhost/" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; from browser you should get something like this &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry5wbth5iono2bf4tdr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry5wbth5iono2bf4tdr8.png" alt="Alt CustomImage"&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;h4&gt;
  
  
  Persistent data
&lt;/h4&gt;

&lt;p&gt;Containers by design are short lived and immutable(redeploy not change). this design puts the need for persistent data as separate concern, and there are two solution provided by Docker for persistent data namely &lt;code&gt;Bind Mount&lt;/code&gt; and &lt;code&gt;Volumes&lt;/code&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  Bind Mount
&lt;/h5&gt;

&lt;p&gt;Is a way of mounting host machines file system in to a container. while this is not often used in production it is better way for local testing and development. lets take a look at example by running the following command inside root directory of Example-7&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --rm --publish 8080:80 --volume ${pwd}:/usr/share/nginx/html/ nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the container is running if the &lt;code&gt;index.html&lt;/code&gt; file is updated in the host machine those changes will be reflected from the running container as well. for demonstration update the &lt;code&gt;index.html&lt;/code&gt; as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;[Content Updated] Docker is awsome!&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;after these update you can see the changes from browser as shown below&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70izrg7v65xv8jn0g9b0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70izrg7v65xv8jn0g9b0.png" alt="Alt UpdatedBindMount"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt; for referencing current directory when &lt;code&gt;Bind Mapping&lt;/code&gt; from CLI&lt;br&gt;
  ${pwd} - PowerShell&lt;br&gt;
  $(pwd) - Mac/Linux&lt;br&gt;
   %cd%  - Command Prompt &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;
  
  
  Volumes
&lt;/h5&gt;

&lt;p&gt;Similar to Bind Mount volumes are another means of persisting data. The distinction from that of bind mount is that volumes are managed by Docker Bind Mount on the other hand are reliant on specifying the destination path on the host machine.&lt;/p&gt;

&lt;p&gt;The first place to specify volume is in the &lt;code&gt;Dockerfile&lt;/code&gt; by using the &lt;code&gt;VOLUME&lt;/code&gt; command. the &lt;code&gt;Dockerfile&lt;/code&gt; of databases (such as postgres, mysql) are setup to include volume.&lt;/p&gt;
&lt;h5&gt;
  
  
  Example-8
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --rm --env POSTGRES_PASSWORD=test-password postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Will start postgres container, then we can check for the volumes using the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker volume ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make things even more interesting we can inspect the volume as well&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker volume inspect [VOLUME_NAME]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look like this&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gdqwqhg36qnpsfyc580.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gdqwqhg36qnpsfyc580.png" alt="Alt Unnamed Volume"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you might have noticed the problem with this is the name of the volume is not readable. this can be fixed by naming the volume using the following command&lt;/p&gt;
&lt;h5&gt;
  
  
  Example-9
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --rm --env POSTGRES_PASSWORD=test-password --volume my-db-volume:/var/lib/postgresql/data postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;if we now inspect the volume it will look as follows&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofnvc5wc4sakau52my37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofnvc5wc4sakau52my37.png" alt="Alt Named Volume"&gt;&lt;/a&gt;&lt;br&gt;
Which is more readable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; the syntax difference between &lt;code&gt;Bind Mount&lt;/code&gt; &amp;amp; &lt;code&gt;Named Volume&lt;/code&gt; Is that the host path of &lt;code&gt;Bind Mount&lt;/code&gt; is preceded by &lt;code&gt;/&lt;/code&gt;(on Mac/Linux) or by &lt;code&gt;//&lt;/code&gt;(on windows).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Network
&lt;/h4&gt;

&lt;p&gt;Docker network is basically a way of making the running containers accessible from the outside world(it could be the internet or local network) and enables containers communicate to each other. of-course there is a lot more to it but I will not go deep in this article.&lt;br&gt;
Creating virtual network is as easy as running &lt;code&gt;create&lt;/code&gt; command as shown below&lt;/p&gt;
&lt;h5&gt;
  
  
  Example-10
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create my-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can run multiple containers in side this container by running the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --rm --network my-network --name nginx1 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container run --rm --network my-network --name nginx2 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; Running containers in the same virtual network can communicate to each other by using the container name as a domain name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since both containers (&lt;code&gt;nginx1&lt;/code&gt;, &lt;code&gt;nginx2&lt;/code&gt;) are on the same virtual network it is possible to use the container name as domain name and to communicate between containers. from Example-5 we can use the &lt;code&gt;exec&lt;/code&gt; command to open bash &amp;amp; run &lt;code&gt;Curl&lt;/code&gt; and see if we can reach the other container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker container exec -it nginx1 bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;/div&gt;



&lt;p&gt;The result is shown below&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nk89zmz6znveal590nv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nk89zmz6znveal590nv.png" alt="Alt Container communication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; Bridge(or Docker0) is the default docker virtual network &amp;amp; it doesn't support the usage of container name as a domain name even if the container are running in the same virtual network. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next section is about Docker compose, but before that cheers on reading this far, most of the important fundamentals are covered. as you will come to see docker compose is only a more organized way of doing the previously mentioned points. lets get to it... &lt;/p&gt;
&lt;h3&gt;
  
  
  Docker Compose
&lt;/h3&gt;

&lt;p&gt;Is a simplified way of managing multiple containers at the same time. docker-compose works fine both in production and local development. docker-compose comprises &lt;code&gt;yml&lt;/code&gt; configuration file and &lt;code&gt;CLI&lt;/code&gt; tool to manage containers using the configuration file. &lt;br&gt;
configuration file syntax overview&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version:[] 
services: 
   service_name1:
         .
         .
   service_name2:
         . 
         . 
   service_nameN:
volumes:
   named_volume1:
   named_volume2:
        .
        .
   named_volumeN:
networks:
   network1:
   netwprk2:
      .
      .
   networkN:     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For better understanding of the general syntax defined above lets take a look at an example. for this example create file called &lt;code&gt;docker-compose.yml&lt;/code&gt; in the same directory as &lt;a href="https://dev.toexample-7"&gt;Example-7&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Example-11
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.4"                                       # Specifies the docker compose file format
services: 
    nginx-simple:                                    # Service name
        image: nginx                                 # Image name &amp;amp; docker checks if image is available locally if not image will be pulled first 
        ports:                                       # Expose ports to make services accssible from outside. the port mapping is read as map host's port 80 to container port 80 
          - 80:80                                    # host_port:container_port
    nginx-bindmount:
        image: nginx
        volumes:                                     # defines the volume for the container   
          - .:/usr/share/nginx/html                  # BindMapping of the files in the current directory(in host) into containers path (which is /usr/share/nginx/html). the "." indicates current host directory  
        ports: 
          - 5005:80
        depends_on:                                  # defines the priority of the services. in this case nginx-bindmount is dependent on nginx-simple therefor nginx-simple has to start first
          - nginx-simple                             # list of services that nginx-bindmount is dependent up on
    nginx-custom-image:                  
        build:                                       # Tells docker we want to build the image from local Dockerfile
          context: .                                 # Defines the directory of the Dockerfile in the host machine. "." indicates current host dircetory 
          dockerfile: Dockerfile                     # name of the Dockerfile
        ports: 
          - 5006:80
    nginx-named-volume:                              
        image: mysql
        volumes: 
          - db-volume:/var/lib/mysql                 # defines named volume called db-volume for nginx-named-volume service to store persistent data
        environment:                                 # passes list of environment variables into nginx-named-volume service
          - MYSQL_ROOT_PASSWORD=my-password          # enviroment variable variable_key=value, in this case MYSQL_ROOT_PASSWORD is variable key &amp;amp; my-password is the corresponding value   

volumes:                                             # defines list the named volumes
   db-volume:                                        # entrie of named volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope the comments on the compose file are explanatory enough for each entries. now by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will start all containers &amp;amp; setup all volumes, networks. yeah! it is that simple. &amp;amp; to clean up everything(container, volume &amp;amp; networks) use the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker compose&lt;/code&gt; also contains &lt;code&gt;start&lt;/code&gt; &amp;amp; &lt;code&gt;stop&lt;/code&gt; commands to start and stop services with out cleaning up everything.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: &lt;code&gt;docker compose&lt;/code&gt; doesn't attach the services with docker's default virtual network(called &lt;code&gt;bridge&lt;/code&gt;) rather it creates it own network and runs the services in that network. that way the services in the same &lt;code&gt;docker-compose&lt;/code&gt; configuration file can communicate with each other by using the &lt;code&gt;Service name&lt;/code&gt; as domain name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Swarm
&lt;/h3&gt;

&lt;p&gt;From the previous section we have seen how to setup and manage image as well as containers and finally using docker compose to manage multiple containers and images. while that all good it doesn't address a couple of problem that surface when using docker, such as&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Easily scaling up and down&lt;/li&gt;
&lt;li&gt;Restarting container if it fails &lt;/li&gt;
&lt;li&gt;Deployment with zero down time&lt;/li&gt;
&lt;li&gt;Secure communication between containers&lt;/li&gt;
&lt;li&gt;Manage which container runs where&lt;/li&gt;
&lt;li&gt;Storing sensitive information &amp;amp; making it accessible only to specific container&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's where &lt;code&gt;Swarm mode&lt;/code&gt; comes to the picture and address the problems stated above. Swarm is docker built in clustering solution. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Manager Nodes&lt;/strong&gt;: are nodes with proper authorization and configuration to manage swarm.&lt;br&gt;
&lt;strong&gt;Workers Nodes&lt;/strong&gt;: are nodes with responsibility to carry out a task and no authority to administer the swarm.&lt;br&gt;
&lt;strong&gt;Raft Database&lt;/strong&gt;: Is a database the resides on every manager nodes, It comprises manager node's configuration that guarantee's their authority.                &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By default Swarm mode is not enabled. to enable swarm mode run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker swarm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is multiple ways to setup the swarm, but for demonstrating some of the basics I will use &lt;a href="https://www.docker.com/play-with-docker" rel="noopener noreferrer"&gt;Play with Docker&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Example-12
&lt;/h4&gt;

&lt;p&gt;Create multiple instances in the docker lab and to initialize the swarm run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker swarm init --advertise-addr 192.168.0.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The IP Address has to be public IP so other instances can join to that swarm(in my case it happens to be &lt;code&gt;192.168.0.8&lt;/code&gt;).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwjncjx4ommpr1uyx3my.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwjncjx4ommpr1uyx3my.png" alt="Alt Create Swarm"&gt;&lt;/a&gt;&lt;br&gt;
Once swarm is created other instances can join using the command generated after creating the swarm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker swarm join --token [TOKEN] [IP_ADDRESS]


docker swarm join --token SWMTKN-1-64cek9j9nfuysu5v76ydgqxn16te1tfwcyv1beqks023dh1yz2-0y6lj91cx03iwbu53btmsmdm3 192.168.0.8:2377
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx0bpozntkvnfhfj85lr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx0bpozntkvnfhfj85lr.png" alt="Alt Joining swarm"&gt;&lt;/a&gt;&lt;br&gt;
After joining the two instances into the swarm we can see the nodes in the swarm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker node ls
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnontw1ogg9wcifwnbzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnontw1ogg9wcifwnbzu.png" alt="Alt Swarm nodes"&gt;&lt;/a&gt;&lt;br&gt;
With in the swarm we can now create multiple services with out worrying about the container distribution because that will be handled by the swarm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker service create --publish 80:80 --replicas 3 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create three containers of nginx and distribute the containers into the instances with in the swarm. to see active services list&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker service ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see more information's of particular service run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker service ps [SERVICE_NAME | SERVICE_ID]
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vpjt2cfmqpj3tvai9pj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vpjt2cfmqpj3tvai9pj.png" alt="Alt Multiple service"&gt;&lt;/a&gt;&lt;br&gt;
As shown above there is 3 replicas of &lt;code&gt;nginx&lt;/code&gt; and they are running on different instances. by updating the number of replicas we can easily scale up and scale down. even more intersting if a container fails in the swarm for some reason it will then be recreated automatically. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgxthc3mvomwk5k725y4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgxthc3mvomwk5k725y4.png" alt="Alt Stopping containers"&gt;&lt;/a&gt;&lt;br&gt;
And if we see the list of containers again&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnoji5jgvcnpd4wemgn7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnoji5jgvcnpd4wemgn7c.png" alt="Alt Restarted container"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is only the tip of the iceberg, there is a lot more you can do with swarm(such as using secrets using docker-compose with swarm) which could not be explained in one article. but I hope this is enough to give you an idea of what Swarm is &amp;amp; its importance.  &lt;/p&gt;

&lt;p&gt;Thanks for reading. Cheers!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>container</category>
      <category>swarm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Serving DocFX Static Site From .NET With Authentication</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Wed, 16 Jun 2021 12:58:56 +0000</pubDate>
      <link>https://dev.to/bazen/serving-docfx-from-net-to-add-authentication-2pak</link>
      <guid>https://dev.to/bazen/serving-docfx-from-net-to-add-authentication-2pak</guid>
      <description>&lt;p&gt;DocFX is a static site generator from source code files and markdown. Its primary use is for documentation. However, it is essential to mention that it is flexible and is applicable for many different purposes. Some use it for blogging and profile sites. It is really up to you to define what to use it for. For more information on &lt;code&gt;DocFX&lt;/code&gt; you can visit their &lt;a href="https://dotnet.github.io/docfx/" rel="noopener noreferrer"&gt;official website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Serve It From .NET?
&lt;/h2&gt;

&lt;p&gt;There are different advantages to serving the static site generated by &lt;code&gt;DocFX&lt;/code&gt; from &lt;code&gt;.NET&lt;/code&gt; since it allows adding different functionalities on top of the static site. One practical advantage is adding authentication to access the static site. The reason for adding the authentication could be that you have internal documentation within your company and want it to be accessible only by authorized persons. This scenario is only to demonstrate a practical use case, &amp;amp; the use case can be different depending on your scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-request
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://identityserver4.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;IdentityServer4&lt;/a&gt;: For authentication&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dotnet.github.io/docfx/" rel="noopener noreferrer"&gt;DocFX&lt;/a&gt;: For generating static site&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;DocFX&lt;/code&gt; to environment variable for smooth build process&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I used &lt;code&gt;IdentityServer4&lt;/code&gt; for authentication in this article, however this implementation works fine with other methods of authentications as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up IdentityServer4
&lt;/h2&gt;

&lt;p&gt;Create IdentityServer4 project&lt;/p&gt;

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

dotnet new is4inmem &lt;span class="nt"&gt;-n&lt;/span&gt; Identity


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

&lt;/div&gt;

&lt;p&gt;The templates for &lt;code&gt;IdentityServer4&lt;/code&gt; projects is available on &lt;a href="https://github.com/IdentityServer/IdentityServer4.Templates" rel="noopener noreferrer"&gt;IdentityServer's Github repo&lt;/a&gt;. After creating the identity project we don't need to make further change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Static site server
&lt;/h2&gt;

&lt;p&gt;Create ASP.NET Api project&lt;/p&gt;

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

dotnet new webapi &lt;span class="nt"&gt;-n&lt;/span&gt; StaticSiteServer


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

&lt;/div&gt;

&lt;p&gt;Add reference to &lt;code&gt;Microsoft.AspNetCore.Authentication.OpenIdConnect&lt;/code&gt; NuGet package.&lt;/p&gt;

&lt;p&gt;There are a couple of changes to be made here and there when setting up the authentication. Not to go off topic, I will not cover that in this article. However, the source code can be found in my &lt;a href="https://github.com/tbazen/serve-docfx-net" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up static site
&lt;/h2&gt;

&lt;p&gt;In the same directory as &lt;code&gt;StaticSiteServer&lt;/code&gt; create static site project:&lt;/p&gt;

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

docfx init &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; Docs


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Setting up the build process
&lt;/h3&gt;

&lt;p&gt;Let's update &lt;code&gt;StaticSiteServer.csproj&lt;/code&gt; to define the root directory of the &lt;code&gt;DocFX&lt;/code&gt; file system:&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;PropertyGroup&amp;gt;&lt;/span&gt;
      .
      .
      .
    &lt;span class="nt"&gt;&amp;lt;DocFXRoot&amp;gt;&lt;/span&gt;Docs\&lt;span class="nt"&gt;&amp;lt;/DocFXRoot&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Next, let's update the &lt;code&gt;StaticSiteServer.csproj&lt;/code&gt; to generate static site on both during build &amp;amp; publish.&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;Content&lt;/span&gt; &lt;span class="na"&gt;Remove=&lt;/span&gt;&lt;span class="s"&gt;"$(DocFXRoot)**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Remove=&lt;/span&gt;&lt;span class="s"&gt;"$(DocFXRoot)**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"$(DocFXRoot)**"&lt;/span&gt; &lt;span class="na"&gt;Exclude=&lt;/span&gt;&lt;span class="s"&gt;"$(DocFXRoot)_site\**"&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&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"DebugEnsureDocFXEnv"&lt;/span&gt; &lt;span class="na"&gt;BeforeTargets=&lt;/span&gt;&lt;span class="s"&gt;"Build"&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(Configuration)' == 'Debug' And !Exists('$(DocFXRoot)node_modules') "&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;Command=&lt;/span&gt;&lt;span class="s"&gt;"docfx --version"&lt;/span&gt; &lt;span class="na"&gt;ContinueOnError=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Output&lt;/span&gt; &lt;span class="na"&gt;TaskParameter=&lt;/span&gt;&lt;span class="s"&gt;"ExitCode"&lt;/span&gt; &lt;span class="na"&gt;PropertyName=&lt;/span&gt;&lt;span class="s"&gt;"ErrorCode"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Exec&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Error&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"'$(ErrorCode)' != '0'"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"DocFX is required to build and run this project. To continue, please install DocFX from https://github.com/dotnet/docfx/releases, and then restart your command prompt or IDE."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Message&lt;/span&gt; &lt;span class="na"&gt;Importance=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Generate static sites from Markdown and code files. This may take several minutes..."&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;"$(DocFXRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"docfx build"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Target&amp;gt;&lt;/span&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;"PublishRunWebpack"&lt;/span&gt; &lt;span class="na"&gt;AfterTargets=&lt;/span&gt;&lt;span class="s"&gt;"ComputeFilesToPublish"&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;"$(DocFXRoot)"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"docfx build"&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;DistFiles&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"$(DocFXRoot)_site\**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ResolvedFileToPublish&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"@(DistFiles-&amp;gt;'%(FullPath)')"&lt;/span&gt; &lt;span class="na"&gt;Exclude=&lt;/span&gt;&lt;span class="s"&gt;"@(ResolvedFileToPublish)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;RelativePath&amp;gt;&lt;/span&gt;%(DistFiles.Identity)&lt;span class="nt"&gt;&amp;lt;/RelativePath&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToPublishDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToPublishDirectory&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ExcludeFromSingleFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/ExcludeFromSingleFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ResolvedFileToPublish&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;Now, with these changes, the build will generate the static site. However, the &lt;code&gt;StaticSiteSeserved&lt;/code&gt;  web API is not serving the static site. To server the static site, let's update the &lt;code&gt;ConfigureServices&lt;/code&gt; method in the &lt;code&gt;Startup.cs&lt;/code&gt; file. Moreover, we will add authorization:&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;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&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;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&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;=&amp;gt;&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="n"&gt;FallbackPolicy&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;AuthorizationPolicyBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthenticatedUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="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;p&gt;Again in the &lt;code&gt;Startup.cs&lt;/code&gt; file let's update the &lt;code&gt;Configure&lt;/code&gt; method to serve static files.&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;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IApplicationBuilder&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IWebHostEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&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;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseFileServer&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;FileServerOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FileProvider&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;PhysicalFileProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentRootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"Docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"_site"&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;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;code&gt;app.UseFileServer*&lt;/code&gt; must be added after &lt;code&gt;app.UseAuthentication()&lt;/code&gt; and &lt;code&gt;app.UseAuthorization()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. When accessing the &lt;code&gt;StaticSiteServer,&lt;/code&gt; the user is redirected for authentication. After authenticating, the user can access the static site, as shown below:&lt;/p&gt;

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

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

&lt;p&gt;&lt;strong&gt;3. Documentation static site&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt2skszcovhs9xc02cyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt2skszcovhs9xc02cyc.png" alt="Alt Documentation static site1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Documentation static site&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7fmr61bs3s7wavr4k1f5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7fmr61bs3s7wavr4k1f5.png" alt="Alt Documentation static site2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete source code can be found on &lt;a href="https://github.com/bazen-teklehaymanot/serve-docfx-net" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading, cheers!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>docfx</category>
      <category>staticsite</category>
      <category>auth</category>
    </item>
    <item>
      <title>Conditional Rendering In React With No Library</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Thu, 29 Apr 2021 18:27:13 +0000</pubDate>
      <link>https://dev.to/bazen/conditional-rendering-in-react-made-easier-and-reusable-no-library-4848</link>
      <guid>https://dev.to/bazen/conditional-rendering-in-react-made-easier-and-reusable-no-library-4848</guid>
      <description>&lt;p&gt;If you ever worked with react it is likely that at some point you implemented some conditional rendering. such as the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="c1"&gt;//&lt;/span&gt;
   &lt;span class="c1"&gt;// Some logic&lt;/span&gt;
   &lt;span class="c1"&gt;//&lt;/span&gt;
   &lt;span class="k"&gt;return &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;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&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;LoadingComponent&lt;/span&gt;&lt;span class="p"&gt;/&amp;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;Content&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is fine.it is limited to two values(&lt;code&gt;true&lt;/code&gt; &amp;amp; &lt;code&gt;false&lt;/code&gt;) which is not always the case. moreover it complicates the component code as our component grows. lets see at other way of implementing this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ConditionalRendererProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;activeState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;mapping&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ConditionalRenderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ConditionalRendererProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea behind this implementation is to use &lt;code&gt;ConditionalRenderer&lt;/code&gt; as a wrapper component and pass a &lt;code&gt;mapping&lt;/code&gt; and &lt;code&gt;activeState&lt;/code&gt; as a props.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;mapping&lt;/code&gt; as its name indicates it contains state to component mapping. meaning what component corresponds to a given state.&lt;br&gt;
&lt;code&gt;activeState&lt;/code&gt; is selected state from the mapping props&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this could seem over complicating the implementation. it is actually more flexible that the first implementation and makes our code more cleaner. well how? okay to answer that lets take a look at another more common scenario where we need conditional rendering. when we have task that needs sometime to complete(e.g. when making API request). in this scenario there is more than two states for now to keep things simple lets agree we have four states namely &lt;code&gt;initial&lt;/code&gt;, &lt;code&gt;processing&lt;/code&gt;, &lt;code&gt;complete&lt;/code&gt; &amp;amp; &lt;code&gt;error&lt;/code&gt; &amp;amp; we want to render different components depending on the active state&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;StateTypes&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Init&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Success&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Processing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PROCESSING&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;StateTypes&lt;/code&gt; enum defines all possible states, next lets define generic wrapper component for components containing asynchronous actions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StateMachineWrapperProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;asyncTask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StateMachineWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StateMachineWrapperProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;machine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useAsync&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asyncTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return &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;ConditionalRenderer&lt;/span&gt;
        &lt;span class="na"&gt;activeState&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;StateTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Fragment&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;StateTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Processing&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;,
          [StateTypes.Error]: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;,
          [StateTypes.Success]: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nt"&gt;component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        }}
    /&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;StateMachineWrapper&lt;/code&gt; renders components that comprises async actions.&lt;br&gt;
It is highly likely that we have multiple components that communicate to an external API or perform some other async task and for every component we can use the &lt;code&gt;StateMachineWrapper&lt;/code&gt; component and separate the side effect from our core component. lets see the usage...&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;longRunningTask&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;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Async task completed&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="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep things simple the long running task does nothing practical but it is easy to modify the implementation according to your use case. finally lets take a look at the core component...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ContentProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ContentWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &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;StateMachineWrapper&lt;/span&gt; 
        &lt;span class="na"&gt;asyncTask&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;longRunningTask&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="si"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;Content&lt;/code&gt; component is pure component and is decoupled with the side effect(or &lt;code&gt;longRunningTask&lt;/code&gt;). as you can see the initial effort pays off finally because the components that mimic the &lt;code&gt;StateMachineWrapper&lt;/code&gt; are pure components and the concerns are separated. this is one use case to demonstrate the ease of implementing conditional rendering in such a way.&lt;/p&gt;

&lt;p&gt;Github gist can be found &lt;a href="https://gist.github.com/bazen-teklehaymanot/38e29b3dd4b9d08a02c2f0cbf7b0aedd" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading, cheers!  &lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>IdentityServer4,ASP.NET Identity for Authentication &amp; Authorization with ReactJS client</title>
      <dc:creator>Bazen</dc:creator>
      <pubDate>Sat, 20 Feb 2021 21:05:03 +0000</pubDate>
      <link>https://dev.to/bazen/identityserver4-asp-net-identity-for-authentication-authorization-with-reactjs-client-4j53</link>
      <guid>https://dev.to/bazen/identityserver4-asp-net-identity-for-authentication-authorization-with-reactjs-client-4j53</guid>
      <description>&lt;p&gt;Very recently I had a scenario where I have to implement two web apps. for both apps I had to implement authentication and authorization. I spent quite sometime researching on what is the better way to implement this &amp;amp; I hope this saves your time for anyone interested. anyway after doing my research I decided to use the following technologies...&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;&lt;a href="https://identityserver.io/" rel="noopener noreferrer"&gt;IdentityServer4&lt;/a&gt;&lt;/strong&gt;  :- for authentication &amp;amp; authorization&lt;br&gt;
2) &lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;ASP.NET Identity&lt;/a&gt;&lt;/strong&gt; :- User information storage &lt;br&gt;
3) &lt;strong&gt;&lt;a href="https://dotnet.microsoft.com/apps/aspnet/apis" rel="noopener noreferrer"&gt;.NET API&lt;/a&gt;&lt;/strong&gt;         :- API protected by IdentityServer4&lt;br&gt;
4) &lt;strong&gt;&lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt;&lt;/strong&gt; :- React &amp;amp; Typescript Client App that is going to consume API  &lt;/p&gt;

&lt;p&gt;Lets start coding...&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Identity Server
&lt;/h2&gt;

&lt;p&gt;We can either create empty project and do all the work by our self or we can use the one of the &lt;a href="https://github.com/IdentityServer/IdentityServer4.Templates" rel="noopener noreferrer"&gt;IdentityServer4 templates&lt;/a&gt;.to keep things simple I'm going to use one of the templates by running the following commands.&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 &lt;span class="nt"&gt;-i&lt;/span&gt; identityserver4.templates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the installed templates run&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 &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are couple of template options to choose from.in this case we want to use ASP.NET Identity as the user data storage so we will run this command:&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 is4aspid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our project ready its time to edit some of the code. find &lt;code&gt;Config.cs&lt;/code&gt; file which contains the identity configuration. the first this we are going to do is to add the Api resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ApiResource&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ApiResources&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ApiResource&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ApiResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample.api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sample Api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Scopes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ProtectedApiScopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScannerApiScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="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;Next step is to add our Client SPA app to the clients list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Clients&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ClientId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sample.spa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ClientName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Sample SPA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;AllowedGrantTypes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GrantTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implicit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;AllowAccessTokensViaBrowser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;RequireConsent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;AccessTokenLifetime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;RedirectUris&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"http://localhost:3000"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;PostLogoutRedirectUris&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"http://localhost:3000"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;AllowedCorsOrigins&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"http://localhost:3000"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;AllowedScopes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;IdentityServerConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardScopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;IdentityServerConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardScopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is enough change for the identity configuration, now we have to add our configuration to &lt;code&gt;IServiceCollection&lt;/code&gt; in &lt;code&gt;StartUp.cs&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddIdentityServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDeveloperSigningCredential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryPersistedGrants&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;             
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryIdentityResources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetIdentityResources&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryApiResources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetApiResources&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryClients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetClients&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAspNetIdentity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production its better to store your identity server configuration in the database, but lets keep things simple for now.we are done configuring the identity server, next step is to create &amp;amp; setup the .NET api project.project can be created by running the following command:&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 webapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the project we have to add reference to the &lt;code&gt;IdentityServer4.AccessTokenValidation&lt;/code&gt; package.we can then add configuration in the &lt;code&gt;StartUp.cs&lt;/code&gt; file by adding the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddIdentityServerAuthentication&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;=&amp;gt;&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="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:5000"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//Identity Server Uri&lt;/span&gt;
         &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireHttpsMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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="n"&gt;ApiName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sample.api"&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;That's it now we can simply guard any end point by adding &lt;code&gt;[Authorize]&lt;/code&gt; attribute on top of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"You are authenticated"&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;Next step is to create &amp;amp; setup our react app by running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app sample-spa &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create react-app my-app &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the react app. we will add the best oidc library called &lt;a href="https://www.npmjs.com/package/oidc-react" rel="noopener noreferrer"&gt;oidc-react&lt;/a&gt; which is the best oidc library I have seen by far.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install oidc-react&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;oidc-config.ts&lt;/code&gt; file in the src directory of sample-spa project and add the following configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customOidcConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthProviderProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample.spa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;automaticSilentRenew&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="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;responseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openid profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:5000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onBeforeSignIn&lt;/span&gt;&lt;span class="p"&gt;:()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="cm"&gt;/**
      * This method gets executed before signin redirecting begins
      * it can be used to store Uri
      */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;onSignIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PATH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[ LOGIN: SUCCESS ]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="p"&gt;};&lt;/span&gt;
         &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[ LOGIN: ERRNO ]&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="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;onSignOut&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AuthProviderSignOutProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[ SignOutOpts ]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Next step is to initiate login using the configuration above. find &lt;code&gt;App.tsx&lt;/code&gt; file and update it using the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;customOidcConfig&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthCheck&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;          
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will automatically initiate the login process. we can also check if the user is logged in by using &lt;code&gt;useAuth&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return &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;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt; 
          &lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
          &lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Authenticated&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
        &lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
          &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Not Authenticated&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are done. I hope you enjoyed this. &lt;br&gt;
Thanks for reading&lt;/p&gt;

&lt;p&gt;Happy Coding!!!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>react</category>
      <category>typescript</category>
      <category>security</category>
    </item>
  </channel>
</rss>
