<?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: Eduard Stefanescu</title>
    <description>The latest articles on DEV Community by Eduard Stefanescu (@eduardstefanescu).</description>
    <link>https://dev.to/eduardstefanescu</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%2F318704%2F51872928-4576-4573-bfd8-881b6b1406e9.jpg</url>
      <title>DEV Community: Eduard Stefanescu</title>
      <link>https://dev.to/eduardstefanescu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eduardstefanescu"/>
    <language>en</language>
    <item>
      <title>ASP.NET Core Swagger Documentation with Bearer Authentication</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sat, 15 Jan 2022 08:55:26 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/aspnet-core-swagger-documentation-with-bearer-authentication-40l6</link>
      <guid>https://dev.to/eduardstefanescu/aspnet-core-swagger-documentation-with-bearer-authentication-40l6</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://eduardstefanescu.dev/2022/01/15/asp-dotnet-core-swagger-documentation-with-authentication/" rel="noopener noreferrer"&gt;&lt;em&gt;https://eduardstefanescu.dev&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on January 15, 2022.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous article, we added Swagger Documentation to an existing ASP.NET Core project. This article will use the previous article and the JWT Authentication Symmetric Key source code to add to a project that already have Swagger Documentation the Authentication feature. These two article can be found here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Swagger Documentation Authentication feature will be introduced briefly in the first section of this article, and its implementation will be discussed in the second section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;As is described in the previous article, Swagger Documentation is a handy tool that generates documentation in a friendly manner from an XML file generated by the .NET Framework. But what if the described API has authentication, then the documentation should have it too. &lt;a href="https://www.nuget.org/packages/Swashbuckle.AspNetCore.SwaggerGen/" rel="noopener noreferrer"&gt;Swashbuckle.AspNetCore.SwaggerGen&lt;/a&gt; package provides the authentication feature, but this article will cover only the Bearer Authentication setup.&lt;/p&gt;

&lt;p&gt;The Swagger Documentation web interface will act as a REST Client, by sending a request to the Authentication endpoint, receiving the Bearer Authentication Token, and then, with this token, we'll have to put it into an input box in order to set the authentication header for the next requests that we'll be making.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the Security Definition
&lt;/h3&gt;

&lt;p&gt;By specifying the security definition, Swagger will take into account that it will have to add the authorization feature. This feature consists of an “Authorize” button at the top of the page that will set the authorization header. The following code will be added in the AddSwaggerGen extension method of the SwaggerGen package.&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;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSecurityDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;securityScheme&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;OpenApiSecurityScheme&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enter the Bearer Authorization string as following: `Bearer Generated-JWT-Token`"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParameterLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SecuritySchemeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Scheme&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Name&lt;/code&gt;&lt;/strong&gt; refers to the name of the header; in this case, the request includes the Authentication header followed by the Bearer Token (i.e., Authorization: Bearer &lt;em&gt;Generated-JWT-Token&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Description&lt;/code&gt;&lt;/strong&gt; is used to help others understand how the authentication works and what value he or she has to enter in the input box;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;In&lt;/code&gt;&lt;/strong&gt; refers to the location of the ApiKey, which in this case will be in the Header. For other authentication types, there might be other options, like query or cookie;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Type&lt;/code&gt;&lt;/strong&gt; is the security scheme that we'll be using;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Scheme&lt;/code&gt;&lt;/strong&gt; is the RFC7235 Hyper Transfer Protocol, that will be used. In this case, we’ll be using the Bearer protocol, but this property also accepts all the other protocols that can be found here: &lt;a href="https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml" rel="noopener noreferrer"&gt;https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This five parameters are required in order to define how the security key will act.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the Security Requirement
&lt;/h3&gt;

&lt;p&gt;The AddSecurityRequirement extension method will add an authorization header to each endpoint when the request is sent. This method takes a dictionary of type Dictionary as a parameter, because the endpoints can have different authentication types (e.g. Basic, Saml). The value of the dictionary is a required list of scope names for the execution only if the security scheme is &lt;code&gt;oauth2&lt;/code&gt; or &lt;code&gt;openIdConnect&lt;/code&gt;. In our case, this list will be an empty one &lt;a href="https://eduardstefanescu.dev/2022/01/15/asp-dotnet-core-swagger-documentation-with-authentication/#reference1" rel="noopener noreferrer"&gt;[1].&lt;/a&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;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSecurityRequirement&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;OpenApiSecurityRequirement&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;OpenApiSecurityScheme&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParameterLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Reference&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;OpenApiReference&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ReferenceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityScheme&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&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 parameters above are required to setup the Security Requirement, but there are more. So Microsoft did a great job by defining all these fields and properties on the OpenAPI.NET GitHub page &lt;a href="https://eduardstefanescu.dev/2022/01/15/asp-dotnet-core-swagger-documentation-with-authentication/#reference2" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; [&lt;a href="https://eduardstefanescu.dev/2022/01/15/asp-dotnet-core-swagger-documentation-with-authentication/#reference3" rel="noopener noreferrer"&gt;3&lt;/a&gt;].&lt;/p&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;The Swagger Documentation API page, can be accessed locally using the following URL: &lt;a href="http://localhost:5000/swagger/index.html" rel="noopener noreferrer"&gt;http://localhost:5000/swagger/index.html&lt;/a&gt;. In the top part of this page, you will notice the “Authorize” button, as in the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A_NfkubVYL0L1m7dO.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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A_NfkubVYL0L1m7dO.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This button will open a pop-up window, where we’ll enter the Bearer Token in order to set the Authorization header. But before doing this, let’s first get the JWT Token from the Authentication endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticating
&lt;/h3&gt;

&lt;p&gt;By opening the Authentication endpoint block from the Swagger Documentation, we can notice an open padlock in the top right corner of the endpoint, representing that there is no Authorization header set yet.&lt;br&gt;&lt;br&gt;
In this opened block, the Try Out button must be clicked in order to open the request section; where the valid username and password should be entered to generate the JWT Token. Otherwise the response code will be Unauthorized, or depending on your implementation it may not generate a valid Token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AkSDNhFRFsAOYbFJB.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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AkSDNhFRFsAOYbFJB.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the picture above, we can see that after executing a valid request, the API responds with OK HTTP Status Code with a Body, that contains the needed Token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization
&lt;/h3&gt;

&lt;p&gt;After generating the JWT Token, now this Token must be copied and we can return to the top of this page. Doing so, we should press the Authorize button, and a pop-up window should be displayed as in the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F661%2F0%2Atn0JVg6YpAy_5a0n.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%2Fcdn-images-1.medium.com%2Fmax%2F661%2F0%2Atn0JVg6YpAy_5a0n.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Value&lt;/em&gt; input box the Authorization header will be set. Firstly as is described in description we need to specify the security scheme, in this case Bearer and after that generated the JWT Token. Then press the Authorize button and close this window to test out if the authentication works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requesting an authorized resource
&lt;/h3&gt;

&lt;p&gt;Now, after authenticating and authorization steps, we can test an endpoint that needs authorization. In this example, the WeatherForecast endpoint will be used. By opening it we can see, that the unlocked padlock is not locked, meaning that we are authorized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Aw-c5XjgU942t_SLE.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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Aw-c5XjgU942t_SLE.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the picture above, is the response of the authorized endpoint. That returns the OK HTTP Status Code with all the available weather forecasts.&lt;/p&gt;

&lt;p&gt;The source code from this article can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/DotnetSwaggerDocumentation/tree/master/API.WithAuthentication" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/DotnetSwaggerDocumentation/tree/master/API.WithAuthentication&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;[1]&lt;a href="https://github.com/microsoft/OpenAPI.NET/tree/master" rel="noopener noreferrer"&gt;https://github.com/microsoft/OpenAPI.NET/tree/master&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2]&lt;a href="https://github.com/microsoft/OpenAPI.NET/blob/master/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs" rel="noopener noreferrer"&gt;https://github.com/microsoft/OpenAPI.NET/blob/master/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[3]&lt;a href="https://github.com/microsoft/OpenAPI.NET/blob/master/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs" rel="noopener noreferrer"&gt;https://github.com/microsoft/OpenAPI.NET/blob/master/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>swagger</category>
    </item>
    <item>
      <title>ASP.NET Core Swagger Documentation</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Wed, 25 Aug 2021 07:56:06 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/aspnet-core-swagger-documentation-194p</link>
      <guid>https://dev.to/eduardstefanescu/aspnet-core-swagger-documentation-194p</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/"&gt;&lt;em&gt;https://eduardstefanescu.dev&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on August 25, 2021.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Romanian version at&lt;/em&gt; &lt;a href="https://www.backto.tech/post/documentarea-codului-%C3%AEn-asp-net-core-folosind-swagger"&gt;&lt;em&gt;https://www.backto.tech/post/documentarea-codului-în-asp-net-core-folosind-swagger&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Documentation is one of the most effective methods for transferring knowledge about an entire project or a subset of it. The documentation can assist others in comprehending how it works and can also be used as a reference for when someone want to verify that his or her assumptions are right.&lt;br&gt;&lt;br&gt;
However, the primary advantage of documenting before or throughout the development process is that it can bring to light issues or ideas that no one else would have considered.&lt;/p&gt;

&lt;p&gt;Thus, this article is about documentation using the Swagger framework; the first section provides an overview, while the second section details the actual implementation. A subsequent article will discuss Swagger documentation with Bearer Token authentication.&lt;/p&gt;
&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Swagger is a component of the &lt;a href="https://www.openapis.org/"&gt;OpenAPI Initiative&lt;/a&gt; and can be used with a variety of other languages, including Java, Spring, and Python. And it includes a number of tools, like &lt;a href="https://app.swaggerhub.com/help/index"&gt;Swagger Hub&lt;/a&gt;, which can be used to define Web APIs without using a programming language to describe it; and &lt;a href="https://swagger.io/docs/swagger-inspector/how-to-use-swagger-inspector/"&gt;Swagger Inspector&lt;/a&gt;, which is a tool for testing API endpoints. However, this article will focus on the &lt;a href="https://swagger.io/docs/specification/about/"&gt;Swagger Specification&lt;/a&gt; in conjunction with ASP.NET.&lt;/p&gt;

&lt;p&gt;The Swagger Specification framework makes use of .NET generated documentation, which I will describe how to enable later, and a UI component that visually illustrates the Web API endpoints, which include the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP method of request (e.g. GET, POST);&lt;/li&gt;
&lt;li&gt;parameters and query parameters;&lt;/li&gt;
&lt;li&gt;response codes (e.g., OK, NotFound);&lt;/li&gt;
&lt;li&gt;a description of the endpoint, its parameters, and the type of return;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;For this article the default ASP.NET Core project was generated, that means the WeatherForecastController will be used in order to describe the API.&lt;br&gt;&lt;br&gt;
As was previously mentioned a file is needed by the Swagger Framework in order to create the documentation. So to generate this file, the GenerateDocumentationFile property in the ASP.NET Core project must be set to true.&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;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PropertyGroup&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="n"&gt;GenerateDocumentationFile&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;GenerateDocumentationFile&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="n"&gt;PropertyGroup&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;By enabling this in the project’s settings file (i.e. csproj), then when the project is being built, the compiler will search for the XML comments and will generate an XML file containing all the written comments &lt;a href="https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/#reference1"&gt;[1]&lt;/a&gt;, in the following format.&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;doc&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;assembly&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;API.WithoutAuthentication&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/assembly&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;members&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;member&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"T:API.WithoutAuthentication.Controllers.WeatherForecastController"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
          List the weather forecasts.
          &lt;span class="nt"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/member&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/members&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/doc&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don’t need to worry too much with the look of this XML file; it’s simply for demonstration purposes.&lt;br&gt;&lt;br&gt;
In the top part, the assembly name is found, meaning that if there are multiple projects, then there will be an XML file for each of them, but only if the GenerateDocumentationFile is enabled.&lt;/p&gt;

&lt;p&gt;And then all the members that have XML comments are listed. Only the constructor of the WeatherForecastController class is described in this case, along with a brief summary. However, if the description had been long, comprising many keys such as param or response, they would have been included as well.&lt;/p&gt;

&lt;p&gt;After enabling this property and rebuilding the project, a few warnings will appear informing us that some type or members must be described, as shown in the image below.&lt;/p&gt;

&lt;p&gt;These warnings are also from classes that don't need to be included in the API documentation, like the Startup or the Program classes, so in order to disable the warnings from these classes, the pragma preprocessor directive must be used, as described below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma warning disable 1591
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pragma directive takes a few parameters, so there is the pragma-name in this case the warnings that have to be disabled, and then the arguments: disable and 1591 &lt;a href="https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/#reference2"&gt;[2]&lt;/a&gt;. The last argument is the warning number, which can be found in the Error List window.&lt;br&gt;&lt;br&gt;
Once the useless warnings are disabled, only the useful ones will be seen. In this from the WeatherForecastController class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zGD-Px0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/915/0%2AXI7GciJ33nZ03pyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zGD-Px0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/915/0%2AXI7GciJ33nZ03pyc.png" alt="" width="880" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After generating the XML file and removing unnecessary warnings, two packages need to be installed in order to generate the Swagger documentation and to visualize it in a more readable way, using a Web page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Swashbuckle.AspNetCore.Swagger/"&gt;Swashbuckle.AspNetCore.Swagger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Swashbuckle.AspNetCore.SwaggerUI/"&gt;Swashbuckle.AspNetCore.SwaggerUI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Writing XML comments
&lt;/h3&gt;

&lt;p&gt;The XML comments needs to clear and to provide enough information in order for those who want to use the API to understand it without having doubts. There might be some misconceptions about writing comments, but in this case writing these comments will help others to understand what the endpoint does and how to use it, because in most cases they will not have access to the code.&lt;br&gt;&lt;br&gt;
Here are some popular websites that published their API Documentation:&lt;/p&gt;
&lt;h3&gt;
  
  
  Describing parameters
&lt;/h3&gt;

&lt;p&gt;In the following code, there is a brief summary about what the constructor of the WeatherForecastController class does and the logger parameter.&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="c1"&gt;// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Constructs the controller state.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;param name="logger"&amp;gt;Injected logger by the dependency injection container.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&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 illustrates how the param tag can be set. If there are many parameters, then another param tag under the previous one has to be added &lt;a href="https://eduardstefanescu.dev/2021/08/25/asp-dotnet-core-swagger-documentation/#reference2"&gt;[3]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then in the code below, the returns and response tags are used for the /GET endpoint. These should be the minimum tags needed to be set on an endpoint in order to describe it in an understandable way.&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="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Get the weather forecast &lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;Returns a list of five weather forecast elements, with random temperatures&lt;/span&gt;
&lt;span class="c1"&gt;/// between -20 and 55 degrees.&amp;lt;/returns&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;response code="200"&amp;gt;Returns the list of weather forecast elements.&amp;lt;/response&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;response code="500"&amp;gt;If an exception is thrown.&amp;lt;/response&amp;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="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Swagger Service Generator
&lt;/h3&gt;

&lt;p&gt;In the Startup class, the Swagger Service Generator must be added, in order to generate the swagger.json file that will be later parsed by a middleware component to display the documentation on a Web page.&lt;br&gt;&lt;br&gt;
For this step, I chose to create an extension method to keep the code organized, but all the code inside this method can be added directly into the Startup class via the ConfigureServices method.&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;IServiceCollection&lt;/span&gt; &lt;span class="nf"&gt;AddSwaggerDocumentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&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="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&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="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"acme"&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;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Acme API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;xmlFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetExecutingAssembly&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.xml"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;xmlFilePath&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;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xmlFile&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="nf"&gt;IncludeXmlComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xmlFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, there are the minimum required options in order to generate the Swagger documentation.&lt;br&gt;&lt;br&gt;
On line 5 the API documentation is set up, with the name, title, and version. Then the XML file path of the current assembly is built and passed to the IncludeXmlComments method as a reference that will be used to generate the swagger.json file. All the available properties of the Service Generator can be found on the Swashbuckle.AspNetCore GitHub page &lt;a href="https://git.io/JftOr"&gt;https://git.io/JftOr&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding Swagger Middleware
&lt;/h3&gt;

&lt;p&gt;As the Swagger Service Generator extension method, there is also one to add two middlewares, one for the Swagger Documentation and another one for the SwaggerUI. These two middlewares can also be added to the Startup class in the Configure method.&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;IApplicationBuilder&lt;/span&gt; &lt;span class="nf"&gt;UseSwaggerDocumentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&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="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;UseSwagger&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;UseSwaggerUI&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="nf"&gt;SwaggerEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/swagger/acme/swagger.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Acme API v1"&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="nf"&gt;DocExpansion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DocExpansion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&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;On line 3 the Swagger Documentation middleware is added, that will provide the swagger.json. And then the Swagger UI is added and configured, by specifying the path to the swagger.json file and the name that will be displayed at the top of the page. Please note that what is in between /swagger/ and /swagger.json is the name of the API Documentation that was previously set in the Swagger Generator Service, in this case, the name is acme. If the name is different, then the Swagger Web Page will display the following error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qV8rMAjz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/506/0%2Ays5dvXqpcClZrHKk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qV8rMAjz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/506/0%2Ays5dvXqpcClZrHKk.png" alt="" width="506" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On line 7 the Expansion option is set to None which will collapse all the API definitions when the Swagger Web Page is opened. This is more of a personal preference. I like to keep those definitions collapsed, because as the application grows, there will be dozens or hundreds of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;After doing all the above steps, the documentation web page can now be accessed by accessing &lt;a href="http://localhost:5000/swagger/index.html"&gt;http://localhost:5000/swagger/index.html&lt;/a&gt;. In the picture below is the landing page with the WeatherForecast panel open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dl5-cv3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/927/0%2ABeO5iWdkhGESHGdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dl5-cv3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/927/0%2ABeO5iWdkhGESHGdz.png" alt="" width="880" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a &lt;em&gt;Try it out&lt;/em&gt; button through which the endpoint can be tested, this is like testing the endpoint with Postman, Insomnia, or any other REST Client, but much more easily, without having to introduce anything. We’ll see that in the next article where the Bearer Authentication will be added, we’ll have to authenticate only once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bM42e8y4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/924/0%2AqZUmjLRPve-ovArg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bM42e8y4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/924/0%2AqZUmjLRPve-ovArg.png" alt="" width="880" height="877"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code from this article can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/DotnetSwaggerDocumentation/tree/master/API.WithoutAuthentcation"&gt;https://github.com/StefanescuEduard/DotnetSwaggerDocumentation/tree/master/API.WithoutAuthentcation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article. If you find it interesting, please share it with your colleagues and friends. Or if you find something that can be improved, please let me know.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;[1] &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc"&gt;https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-pragma"&gt;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-pragma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[3] &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/codedoc"&gt;https://docs.microsoft.com/en-us/dotnet/csharp/codedoc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>openai</category>
      <category>dotnetcore</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Notes on Day 2 - The One with Dotnet @Codecamp Romania, 2021</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Fri, 02 Apr 2021 07:50:21 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/notes-on-day-2-the-one-with-dotnet-codecamp-romania-2021-41co</link>
      <guid>https://dev.to/eduardstefanescu/notes-on-day-2-the-one-with-dotnet-codecamp-romania-2021-41co</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2021/04/02/notes-on-day-2-the-one-with-dotnet-codecamp-romania-2021/"&gt;https://eduardstefanescu.dev/2021/04/02/notes-on-day-2-the-one-with-dotnet-codecamp-romania-2021/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There was a small talk when Raffaele told us what he did in this corona time. So he started working with ML and also Code Generation driven by ML.&lt;/p&gt;

&lt;p&gt;There was also a talk about how ML was involved in the industry. For example, every machine now starts having more user-friendly interfaces and through this more things can be automated to provide a much greater experience to end customers. And also to the factories that can apply ML to simulate a result before creating and applying those concepts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Power your .NET application with the new generation of diagnostics - March 25 14:00 - 14:45 - Raffaele Rialdi&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The session goal was to show how to automate the diagnostic process in production.&lt;/p&gt;

&lt;p&gt;The first step was when to trigger a diagnostic with the DiagnosticClient library. And the second step was that once the data was captured, we can programmatically analyze the process that gave the problem with ClrMD 2.0 library.&lt;/p&gt;

&lt;p&gt;Preemptive profiling or microbenchmark is used on dev machines to analyze specific lines of code that are not performing as expected, by using Benchmark.NET.&lt;/p&gt;

&lt;p&gt;In production, the primary source of help are the logs. But those logs should not be too verbose but also not too short, for example containing too little information.&lt;/p&gt;

&lt;p&gt;A dump can be a solution by using for example dotnet-dump, but it is not a tool for investigating problems, because the problem can be done after analyzing it, and catching the perfect moment is hard.&lt;/p&gt;

&lt;p&gt;In production, the performance can be monitored with dotnet-trace, dotnet-counter and in .NET 5 we can use a new tool dotnet-monitor that can connect to remotely located and locally we can access it through a web interface.&lt;/p&gt;

&lt;p&gt;There is also another problem with dumps because there might be sensitive data, for example, the application could be installed in a hospital, so those data can be constrained by privacy and EU regulation like GDPR.&lt;/p&gt;

&lt;p&gt;The presented scenario was an &lt;a href="http://asp.NET"&gt;ASP.NET&lt;/a&gt; Core application and many clients that use the app. There is also a console application used to stress the web service, that can make concurrent requests. The diagnostic application is receiving TraceEvents from the web service. This application uses two libraries: DiagnosticClient and ClrMD 2.0 (the investigating library, that grabs data). When an issue occurs a snapshot with the web service is created by this diagnostic app. By doing so we can capture the exact moment when the problem occurred.&lt;/p&gt;

&lt;p&gt;The communication between web service and diag app is the communication that can be made with every .NET application starting with .NET Core 3.0.&lt;/p&gt;

&lt;p&gt;The library recommended is &lt;a href="https://github.com/raffaeler/PowerDiagnostics"&gt;https://github.com/raffaeler/PowerDiagnostics&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Diagnostic Demo app was used to capture snapshots and also run different queries to display the root cause of the problem. For example, discovering a big byte array that uses too much memory. Or querying duplicate strings, getting strings by size, list of modules or threads stacks.&lt;/p&gt;

&lt;p&gt;The app can also load a dump saved before and that dump can be investigated as dump saved at the runtime.&lt;/p&gt;

&lt;p&gt;.NET 5 introduces reversed communication protocol, which can be used to diagnose apps, like subscribing to them and when an event occurs, the diagnosis app can read them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The (too) Many Faces of Architecture - March 25 15:00 - 15:45 - Mihaela Ghidersa&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This presentation was a generic one about architecture, discussing different types of architecture.&lt;/p&gt;

&lt;p&gt;Architecture is a technical solution that makes artistic or more abstract concepts materialize.&lt;/p&gt;

&lt;p&gt;In the real world, architecture is creating a small module and combining both technical and business concepts into a big schema or structure.&lt;/p&gt;

&lt;p&gt;The architecture can be seen as a blueprint. We should define what and why is significant.&lt;/p&gt;

&lt;p&gt;The architect is not about the title, he or she has a flexible role, that can collaborate more than giving indications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IflO7_pl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08dltjiihw5o2er37s06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IflO7_pl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08dltjiihw5o2er37s06.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telemetry in .NET distributed applications - March 25 16:00 - 16:45 - Constantin-Ariton Lazar  /  Mihai Detesan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The presentation was focusing on automotive telemetry by using Bosch sensors. &lt;/p&gt;

&lt;p&gt;There was a comparison between the Monolith application and the new way of developing products with microservices.&lt;/p&gt;

&lt;p&gt;One of a problem with microservices is with the coherence, which can be difficult to track because each microservice creates request between them. And for example, if an error occurred is a bit hard to know from where it comes.&lt;/p&gt;

&lt;p&gt;And also another problem comes from debugging and is also difficult to locate.&lt;/p&gt;

&lt;p&gt;In monolith application scaling represents adding more hardware resources, instead of on microservices scaling represents adding more instances of a specific or many microservices.&lt;/p&gt;

&lt;p&gt;The "telemetry" word comes from Greek, tele = distance and metron = measure. The "sum" of this to words can be translated as a process of recording and transmitting some logs or reading of a sensor or even a machine.&lt;/p&gt;

&lt;p&gt;OpenTelemtry is an observability framework that combines traces and metrics.&lt;/p&gt;

&lt;p&gt;Jaeger and Zipkin were used for tracing.&lt;/p&gt;

&lt;p&gt;To trace all microservices, each of them has a Trace Id that uniquely identifies each microservice.&lt;/p&gt;

&lt;p&gt;The trace collector creates some sort of graph from all traces.&lt;/p&gt;

&lt;p&gt;All the Trace IDs are sent from a microservice to another when creating a request, to know which microservice called another one.&lt;/p&gt;

&lt;p&gt;The final id is composed of the Trace Id and the Parent Id.&lt;/p&gt;

&lt;p&gt;Elasticsearch was used to store the logs with Timestamp, Service context like IP or the microservice name, the operation context like the stack trace, and the Trace Id.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's New in C# - March 25 17:00 - 17:45 - Chris Sienkiewicz  /  Fred Silberberg&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In C# there are top-level statements, before declaring usings, namespace, and declaring classes. And those lines are executed. The compiler will take it and put it in a form to execute it.&lt;br&gt;
Even async calls will work in top-level statements because the main method that runs these lines is an async one.&lt;br&gt;
For not including the namespace in the statements we can use using before them.&lt;br&gt;
In top-level statements functions can also be declared. But the functions can be used only in the local top statements. So for example, if there are classes under, those top functions can't be called in. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eNFREYE6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cl7ai503ageto4jh1ktj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eNFREYE6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cl7ai503ageto4jh1ktj.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Because var fields can't be used for declaring fields at the class level. Now those fields can be instantiated only by calling &lt;em&gt;new()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jbVMb9uK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkajtyofpgne5uachal0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jbVMb9uK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkajtyofpgne5uachal0.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The new keyword can also be used to instantiate a class without specifying the name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wMxvaPql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5fndrea1vhrxdhg8hh0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wMxvaPql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5fndrea1vhrxdhg8hh0v.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To avoid overriding the not equal operator (!=) when checking for null, we can verify an object that is not null, by using exactly those keywords "is not null".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ScUH_sVw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7q8bwytpaffjsow2tv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ScUH_sVw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7q8bwytpaffjsow2tv2.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;When comparing two objects to avoid overriding the Equals method, the class can be changed to a record, that represents a class type with value semantics, compares equality by value. This works only to type fields.&lt;br&gt;
A record can be seen as a collection of values.&lt;/p&gt;

&lt;p&gt;There is a new future called initialization only available only to &lt;em&gt;record&lt;/em&gt;, which provides the ability to assign a property only once in the object initialization.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;with&lt;/em&gt; keyword provides non-destructive mutation, that creates a copy of the variable. So values can be set as a part of the initialization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLRlK0-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnw47l44155brlemsfu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLRlK0-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnw47l44155brlemsfu6.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Records offer the possibility to add a property at the declaration level, similar to the constructor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nsEu-5Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwkehi42oqxxk0350xv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nsEu-5Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwkehi42oqxxk0350xv4.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;And the inheritance looks very similar to the constructor, without using the base keyword.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Za7aVPGu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtizg1vftve62pf9mj63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Za7aVPGu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtizg1vftve62pf9mj63.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In C# 10 there can be some of the following futures:&lt;/p&gt;

&lt;p&gt;The namespaces can be declared without braces.&lt;/p&gt;

&lt;p&gt;The global keyword can be used with using to declare a variable or a namespace in a single place. This will make those declarations available all over other files.&lt;/p&gt;

&lt;p&gt;Nullable types can be used in if.&lt;/p&gt;

&lt;p&gt;There can be semi-auto properties that have a backing field, that doesn't need to be declared.&lt;/p&gt;

&lt;p&gt;The records can be also structs (record struct), similar to the current record for classes.&lt;/p&gt;

&lt;p&gt;There can be required properties that uses the &lt;em&gt;required&lt;/em&gt; keyword that requires the user to set it. &lt;/p&gt;

&lt;p&gt;The IAddable interface can be used to "override" the plus sign to perform add operation with which type is needed. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe for Modern Applications: .NET, Azure SQL, Functions, Geospatial, JSON - March 25 18:00 - 18:45 - Anna Hoffman&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The presentation was about creating an application to be notified when a bus arrives.&lt;/p&gt;

&lt;p&gt;The data are imported from the public transportation data. Azure was used for all the below "pieces".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8h980KaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqibmcaf5ukrr655vc7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8h980KaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqibmcaf5ukrr655vc7t.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;For the database, Azure SQL Database was used because it has the multi-model capability and also native geospatial support. And another important point of using Azure SQL Database is the feature of using JSON because the conversion is done automatically (from non-relational to relational).&lt;/p&gt;

&lt;p&gt;Azure Data Studio looks very similar to Jupiter used for Python. It is a notebook where both code (SQL, Powershell) and documentation can be written.&lt;/p&gt;

&lt;p&gt;There are geofences created to be notified when the bus enters them.&lt;/p&gt;

&lt;p&gt;Overall, this was my first Code camp conference and also my first conference online. It was a nice experience, but it is not compared with a real-life conference, where you can see the presenters and even ask them questions after the session.&lt;br&gt;
But if the corona still stays among us, these conferences are a great way to refresh your mind with what's new in technology and in .NET.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>codecampromania</category>
      <category>conference</category>
      <category>technology</category>
    </item>
    <item>
      <title>Notes on Day 1 — The One with Dotnet @Codecamp Romania, 2021</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Fri, 26 Mar 2021 07:53:56 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/notes-on-day-1-the-one-with-dotnet-codecamp-romania-2021-4795</link>
      <guid>https://dev.to/eduardstefanescu/notes-on-day-1-the-one-with-dotnet-codecamp-romania-2021-4795</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2021/03/26/notes-on-day-1-the-one-with-dotnet-codecamp-romania-2021/"&gt;https://eduardstefanescu.dev/2021/03/26/notes-on-day-1-the-one-with-dotnet-codecamp-romania-2021/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  13:45 - 14:00
&lt;/h2&gt;

&lt;p&gt;The first conference day started with Dino Esposito discussing that it matters more the soft skills and the pragmatic way to approach problems rather than the used technology, like .NET.&lt;br&gt;
In a sports business, the money comes from the data, that is applied to the sportsmen and women. All the things that we are seeing on TV look so simple, but all of them are based on data. "Data is gold".&lt;/p&gt;

&lt;p&gt;Data Science is only an umbrella because we need engineering to apply the science and make it available. This definition of Science fits Machine Learning and all those technologies related to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Data) Engineering vs (Data) Science - March 24 14:00 - 14:45 -  Dino Esposito
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Data Science is a starting point, and Data Engineering is the final point.&lt;/li&gt;
&lt;li&gt;Science demonstrates what can be done, and Engineering shows how that works.&lt;/li&gt;
&lt;li&gt;AI is considered to be just software, but it can become intelligent.&lt;/li&gt;
&lt;li&gt;Software that we write today is not as intelligent as ML one.&lt;/li&gt;
&lt;li&gt;The Data Science Teams is working with the dataset.&lt;/li&gt;
&lt;li&gt;Most of the time the algorithm is all right, the problem might be with the web service as a link in a chain that might be broken.&lt;/li&gt;
&lt;li&gt;The role of Data Engineer override with DS and ML Developer. And that is because that guarantees raw data is captured and in the right way to be processed and become a product.&lt;/li&gt;
&lt;li&gt;Data Scientist used techniques from math and stats to view through the raw data available. It can be compared with a sculptor, that takes out marble pieces to make a beautiful sculpture. It might have a view before processing (sculpting) and through the data. The DS should tell the company what can be learned from the data and what can be planned.&lt;/li&gt;
&lt;li&gt;Data Scientist can be viewed as a Product Owner, but for data. Data Scientist should have advanced knowledge in abstract math.&lt;/li&gt;
&lt;li&gt;The company has a team of DS that think can be a great asset with the risk of producing nothing real but coming with ideas.&lt;/li&gt;
&lt;li&gt;In history the Data scientists were done by most of the big kingdom to support expeditions in unknown territories, in the hope of getting a financial return.&lt;/li&gt;
&lt;li&gt;The DE is not expected to have a deep knowledge of math but should have deep knowledge of databases. For example, how to move big data, from Data Lake to Data Warehouse. Should also have skills of how to automate those processes. Should also know knowing how often the expected model should be re-trained to stay adherent to close real data.&lt;/li&gt;
&lt;li&gt;Companies to improve applications need real-world workloads to be scalable enough.&lt;/li&gt;
&lt;li&gt;A role of DS is not enough, the company also needs DE and infrastructure.&lt;/li&gt;
&lt;li&gt;A role is a set of skills of an individual.&lt;/li&gt;
&lt;li&gt;The professional is also about an individual but has the skills to cover a given role.&lt;/li&gt;
&lt;li&gt;The ML Engineer should write good software, applying best practices, and being comfortable with web services technologies like API or gRPC. The ML engineer should also incorporate a trained model into a client application.&lt;/li&gt;
&lt;li&gt;Two interesting ideas about how knowledge can be spread:

&lt;ul&gt;
&lt;li&gt;T-shaped knowledge is a deep vertical in one area and basic knowledge of several other side areas.&lt;/li&gt;
&lt;li&gt;Y-shaped is a deep vertical in one area and good knowledge good enough in a small number of side areas. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;ML.NET comes as a framework to be helpful to data engineers and ML engineers rather than data scientists. ML.NET can manage up to 1TB of data. Is a tool that helps to integrate ML solution inside of existing or new .NET application. ML.NET is not a Microsoft version of Python is a tool for Data Scientists and Data Engineers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Single-tenant to multi-tenant, a real world example - March 24 15:00 - 15:45 - Iris Classon
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nice presentation slides, drawn by her.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sneak peek:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--px3NkUep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lhf82j2wb7vf1skufihc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--px3NkUep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lhf82j2wb7vf1skufihc.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was a discussion about multiple clients that access a load balancer, which redirects them to a cluster that contains an app, and that app shares multiple databases (tenants) to each client.&lt;/li&gt;
&lt;li&gt;The old version of this was by creating an app for each client, that involves too many resources.&lt;/li&gt;
&lt;li&gt;The new architecture looks something like in the above picture.&lt;/li&gt;
&lt;li&gt;The problem with this architecture is that it should be too many instances of the Web API and also the deployment takes half a week. The deployment for aproximetely 120 customers takes 2 to 3 hours.&lt;/li&gt;
&lt;li&gt;To being fixing that problem, she started with the Web API by using multiple tenants. The tenant can be identified by the subdomain, the domain, or a path.&lt;/li&gt;
&lt;li&gt;The later you do it, the easier it is to get it wrong.&lt;/li&gt;
&lt;li&gt;On a previous company all that logic was on-premises and then to a local cloud provider. But now on the current company, the application became tenant agnostic that runs on the cloud and also has a load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost saving for scaling.&lt;/li&gt;
&lt;li&gt;Simplified and faster deploying process.&lt;/li&gt;
&lt;li&gt;Logs should be treated differently because we're not going to have logs per customer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clients are not isolated, so the connection should be encrypted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trailblazor: Building Dynamic Applications with Blazor - March 24 16:00 - 16:45 - Shaun Walker
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic applications are also called plugin applications, modular applications, or dynamic applications.&lt;/li&gt;
&lt;li&gt;The benefits are the extensibility of being loosely coupled, which can be developed in parallel.&lt;/li&gt;
&lt;li&gt;Blazor provides a consistent set of technologies to build both backend and frontend.&lt;/li&gt;
&lt;li&gt;A Razor Component has capabilities such as routing, parameters, binding, and life cycle events.&lt;/li&gt;
&lt;li&gt;The web app in the Blazor Server and the communication with the DOM (Browser) is done with SignalR.&lt;/li&gt;
&lt;li&gt;The newer model done in &lt;a href="http://asp.NET"&gt;ASP.NET&lt;/a&gt; Core, is done by using Web Assembly, and all that code is run in the browser.&lt;/li&gt;
&lt;li&gt;There is an open source app framework build on Blazor called Oqtane. Can be used to create modern web applications with less called. (boilerplates). "Rocket Fuel for Blazor"&lt;/li&gt;
&lt;li&gt;The benefits and the features of Oqtane Framework:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1NIJE3mV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i1uwwkjcyqdejhmi1whb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1NIJE3mV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i1uwwkjcyqdejhmi1whb.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At first look, the razor code looks like aspx code but doesn't have a .cs file. As far as I understood a partial class can be created to move the code from the razor page.&lt;/li&gt;
&lt;li&gt;The Oqtane should be configured like a WordPress site before using it. The configuration is simple, and after that, the administrator is redirected to the admin page, where settings can be made.&lt;/li&gt;
&lt;li&gt;Even the application looks more like WordPress because content can be added from within the website. This a high-level comparison because the website is using Web Assembly so it has much more capabilities than WordPress.&lt;/li&gt;
&lt;li&gt;Also modules can be created in code, deployed to Oqtane, and then added to the website via admin panel. When creating a module from inside the app, a whole solution is created locally on the server machine, with Client, Server, Package all the projects need for the specific module.&lt;/li&gt;
&lt;li&gt;Oqtane is WordPress on extraterrestrial steroids. At first look is so powerful, and a much better comparison it would be with Oracle Apex, but with total control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Moving a 20 year old .NET on Windows blog to Linux, Containers and Azure - March 24 17:00 - 17:45 - Scott Hanselman
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Scott start presenting his website. He started blogging in 2002 with .NET 2.0 and then upgraded to .NET 4.x in a Windows Server.&lt;/li&gt;
&lt;li&gt;Because it was hosted on a Windows Server, he needed to login in with RDP for troubleshooting. At that time this Windows Server was hosted, but not a VM on a physical server.&lt;/li&gt;
&lt;li&gt;One of the requirements when moving to another framework was to not break the URLs.&lt;/li&gt;
&lt;li&gt;There is a .NET Portability Analyzer that helps us find code that can't be moved to a new .NET framework.&lt;/li&gt;
&lt;li&gt;Dotnet try-convert can be used to try to convert a .NET framework project from an old version to a newer one.&lt;/li&gt;
&lt;li&gt;Scott shows how to build the same application in Windows and Ubuntu (WSL) and .NET 5.&lt;/li&gt;
&lt;li&gt;Also some scripts can deploy the blog to Docker containers and can be also hosted to Azure or any cloud provider.&lt;/li&gt;
&lt;li&gt;Azure Front Doors is similar to Cloudflare, which can take different domains and map them to a different backend.&lt;/li&gt;
&lt;li&gt;His /blog is a different Azure App, and this redirect can be done within the same site with Azure Front Doors. Also, the certificate can be owned but managed by Azure.&lt;/li&gt;
&lt;li&gt;The breakdown of the virtual machines was done systematically to not break the website.&lt;/li&gt;
&lt;li&gt;Also by using .NET the website can be moved to any cloud provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture – The Stuff That's Hard To Change - March 24 18:00 - 18:45 - Dylan Beattie
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fred Brooks discussed computer architecture in 1962.&lt;/li&gt;
&lt;li&gt;The stuff that is hard to change are those components that were built wrong and cost money to change them or a part of them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G7alAO36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0m6jl325hp1aemd4tut2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G7alAO36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0m6jl325hp1aemd4tut2.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The architect should look forward and see what's coming.&lt;/li&gt;
&lt;li&gt;To understand software, we should not look at the code because it is time-consuming. We should look at the traffic pattern, such as HTTP requests, load balancing, how many requests supports.&lt;/li&gt;
&lt;li&gt;We need to ask the right question to be turned into meaningful metrics. For example knowing who to protect, for multiple-factor authentication.&lt;/li&gt;
&lt;li&gt;Before reinventing the wheel search for an existing library, for example from nuget.&lt;/li&gt;
&lt;li&gt;Diagrams should be clear, showing exactly what each of the entries should look like. Add more details to the diagrams to be easily understood. &lt;/li&gt;
&lt;li&gt;I recommend following Dylan Beattie on Twitter (&lt;a href="https://twitter.com/dylanbeattie"&gt;https://twitter.com/dylanbeattie&lt;/a&gt;) and the conferences he is attending.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>codecampromania</category>
      <category>conference</category>
    </item>
    <item>
      <title>Notes on Sandro Mancuso — Software Craftsmanship @Talk</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 11:49:42 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/notes-on-sandro-mancuso-software-craftsmanship-talk-48ch</link>
      <guid>https://dev.to/eduardstefanescu/notes-on-sandro-mancuso-software-craftsmanship-talk-48ch</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/05/05/notes-on-sandro-mancuso-software-craftsmanship-talk/"&gt;https://eduardstefanescu.dev/2020/05/05/notes-on-sandro-mancuso-software-craftsmanship-talk/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Talk: &lt;a href="https://www.youtube.com/watch?v=9OhXqBlCmrM"&gt;https://www.youtube.com/watch?v=9OhXqBlCmrM&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/05/notes-on-sandro-mancuso-software-craftsmanship-talk/#Highlights"&gt;&lt;/a&gt;Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  The attitude of software craftsmanship should be: passion, career ownership, "perfect" practice and boy scout rule;&lt;/li&gt;
&lt;li&gt;  We should produce more to receive more, and not waiting to receive something from our company because we are owning our career;&lt;/li&gt;
&lt;li&gt;  When we are working on an organization don't excuse, like "No one does that, so I'm not going to do it also". Either you do it or you leave the company;&lt;/li&gt;
&lt;li&gt;  A good developer is not Java, C# or Ruby developer. A good developer is a developer. We use the tools that we find useful for our job;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/05/notes-on-sandro-mancuso-software-craftsmanship-talk/#Notes"&gt;&lt;/a&gt;Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  In February 2001, 17 people meet in a ski resort in Utah to create an Agile Methodology. The people there were people like Uncle Bob, Martin Fowler;&lt;/li&gt;
&lt;li&gt;  In agile processes and tools became more important than technical practices and excellence;&lt;/li&gt;
&lt;li&gt;  In the beginning there, were more "shits" scrum masters than developers. Some of those scrum masters know nothing about software development;&lt;/li&gt;
&lt;li&gt;  Without agile processes there will be no good delivered software;&lt;/li&gt;
&lt;li&gt;  "Insanity: doing the same thing over and over again, and expecting different results" --- Albert Einstein;&lt;/li&gt;
&lt;li&gt;  When we are under pressure we tend to cut corners, by thinking that we deliver faster, even when the managers do not push us;&lt;/li&gt;
&lt;li&gt;  We think that we don't have, but we do. Is our fault that we think that we don't have, and by doing so, we are delivering low-quality products;&lt;/li&gt;
&lt;li&gt;  Agile is about shorting the feedback loop;&lt;/li&gt;
&lt;li&gt;  By reacting to that feedback is what gives us the agility;&lt;/li&gt;
&lt;li&gt;  Agility is reacting constantly to feedback;&lt;/li&gt;
&lt;li&gt;  We don't do agile, because it's not logical. We are agile;&lt;/li&gt;
&lt;li&gt;  The most important deliver is the software itself;&lt;/li&gt;
&lt;li&gt;  To have good software, we need to have a good process;&lt;/li&gt;
&lt;li&gt;  Businesses are hostages of their software;&lt;/li&gt;
&lt;li&gt;  The business will move as fast as we developers create or change software;&lt;/li&gt;
&lt;li&gt;  As the software grows and no attention paid to the quality of it, the thing is that will become much harder;&lt;/li&gt;
&lt;li&gt;  In agile we are splitting stories, but delivering all the user stories doesn't mean that the delivered software is it the required one or at the quality that we want;&lt;/li&gt;
&lt;li&gt;  Every bug found by the QA team, is something we developers haven't done; QA should contribute in defining user stories and read newspapers;&lt;/li&gt;
&lt;li&gt;  We don't want software that breaks, we want software that makes us happy to work with;&lt;/li&gt;
&lt;li&gt;  Software that makes us happy is not about beautiful code, but instead is easy to maintain, to change and to test;&lt;/li&gt;
&lt;li&gt;  For him, the software is an asset, a huge investment that we need to care about because costs a fortune;&lt;/li&gt;
&lt;li&gt;  It doesn't matter the contract type, the relationship shouldn't be employer and employee, it should be a partnership;&lt;/li&gt;
&lt;li&gt;  We are not keeping the heads down and doing what we are told as in a factory because we are creative people;&lt;/li&gt;
&lt;li&gt;  Every craftsman or professional that are working on a project, he or she should strive to make it a success;&lt;/li&gt;
&lt;li&gt;  Software craftsmanship in his opinion is professionalism in software development;&lt;/li&gt;
&lt;li&gt;  Feedback in software development is based on XP Practices;&lt;/li&gt;
&lt;li&gt;  We should not need the authorization to use practices that improve the quality of the product, like Unit Tests, we should just do it;&lt;/li&gt;
&lt;li&gt;  Managers are interested in value, we are adding value through practices like: TDD, Continuous Integration, Refactoring, Pair Programming, and Automated Tests;&lt;/li&gt;
&lt;li&gt;  When we are talking about business, we should not discuss practices, instead, we should discuss about the value;&lt;/li&gt;
&lt;li&gt;  On a new project, at the beginning we will be slower until we will be better and faster;&lt;/li&gt;
&lt;li&gt;  Quality depends on who is doing the job, not the time or money;&lt;/li&gt;
&lt;li&gt;  "Developers are not football players" and should not cost millions of euros to create quality software;&lt;/li&gt;
&lt;li&gt;  Quality cannot be measure and defined precisely because there are so many variables, it means different people, in different places and different points in time;&lt;/li&gt;
&lt;li&gt;  Code coverage is a dangerous metric and should never be used as a target or management tool because the percentage of tested code is not the same as the percentage of the executed code. For example, we can have 80% tested code from a 50% executed code;&lt;/li&gt;
&lt;li&gt;  "How it is done is as important as having it done" --- Eduardo Namur;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>craftsmanship</category>
      <category>software</category>
    </item>
    <item>
      <title>JWT Token Claims in ASP.NET Core</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 11:48:56 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/jwt-token-claims-in-asp-net-core-1kk8</link>
      <guid>https://dev.to/eduardstefanescu/jwt-token-claims-in-asp-net-core-1kk8</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;After the authentication was presented in the previous two articles using Symmetric and Asymmetric keys, then this article is about authentication, much more exactly about Claims and Roles. In the first part, there will be an introduction to the core concepts of the JWT Claims, and in the second part the actual implementation.&lt;/p&gt;

&lt;p&gt;JWT Authentication with Symmetric Key: &lt;a href="https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/&lt;/a&gt;.\&lt;br&gt;
JWT Authentication with Asymmetric Key: &lt;a href="https://stefanescueduard.github.io/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#Introduction" rel="noopener noreferrer"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;Claims in JWT Token are used to store key data (e.g. username, timezone, or roles) in the Token payload, besides the IssuedAt (i.e. iat), which is added by default.\&lt;br&gt;
In .NET Core, Claims can be used without installing any additional package, it comes from the &lt;code&gt;System.Security.Claims&lt;/code&gt; package. From this package, in this article, just the &lt;code&gt;Claim&lt;/code&gt; and &lt;code&gt;ClaimTypes&lt;/code&gt; will be used. You can find more about them here: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.claims?view=netcore-3.1" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/system.security.claims?view=netcore-3.1&lt;/a&gt;.\&lt;br&gt;
For this article I chose to use &lt;code&gt;JwtAuthentication.AsymmetricEncryption&lt;/code&gt; project from the previous article and to add some functionality to support Claims and Roles. So if you are reading the previous two articles, you'll see small changes in this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#Additional-changes" rel="noopener noreferrer"&gt;&lt;/a&gt;Additional changes
&lt;/h2&gt;

&lt;p&gt;As I said there will be some minor changes, to support the Claims and Roles feature. These changes are not required in your type of scenario but are required for a better understanding of this article. So if your target is to find the actual implementation, you can skip the &lt;code&gt;AuthenticationService&lt;/code&gt; class.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#AuthenticationService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;AuthenticationService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AuthenticationService&lt;/code&gt; now will have an additional &lt;code&gt;UserRepository&lt;/code&gt; from which the data about the &lt;code&gt;User&lt;/code&gt; will be retrieved. And the &lt;code&gt;TokenService&lt;/code&gt; will receive the &lt;code&gt;User&lt;/code&gt; to generate the &lt;code&gt;securityToken&lt;/code&gt;.&lt;/p&gt;

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

public string Authenticate(UserCredentials userCredentials)
{
    userService.ValidateCredentials(userCredentials);
    User user = userRepository.GetUser(userCredentials.Username);
    var tokenService = new TokenService(user);
    string securityToken = tokenService.GetToken();

    return securityToken;
}


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Authenticate&lt;/code&gt; method was explained in the previous two articles and all the code can be found on my GitHub account, there will be a link to it at the end of this article.\&lt;br&gt;
&lt;code&gt;UserRepository&lt;/code&gt; contains a predefined list of users, and the &lt;code&gt;GetUser&lt;/code&gt; method returns only the &lt;code&gt;User&lt;/code&gt; with the given username, this logic was on the &lt;code&gt;UserService&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#User" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;User&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;User&lt;/code&gt; now contains the &lt;code&gt;Roles&lt;/code&gt; property and the &lt;code&gt;Claims&lt;/code&gt; method which will build the claims with the &lt;code&gt;Username&lt;/code&gt; and &lt;code&gt;Roles&lt;/code&gt;. For the sake of this article, we're supposing that the &lt;code&gt;Roles&lt;/code&gt; will be all the time set, so we'll don't need to worry if this collection will be &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

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

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
    public IEnumerable&amp;lt;string&amp;gt; Roles { get; set; }

    public IEnumerable&amp;lt;Claim&amp;gt; Claims()
    {
        var claims = new List&amp;lt;Claim&amp;gt; { new Claim(ClaimTypes.Name, Username) };
        claims.AddRange(Roles.Select(role =&amp;gt; new Claim(ClaimTypes.Role, role)));

        return claims;
    }
}


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

&lt;/div&gt;

&lt;p&gt;You may notice that there are some predefined &lt;code&gt;ClaimTypes&lt;/code&gt;, created by a standard (i.e. &lt;a href="http://docs.oasis-open.org/imi/ns/identity-200810" rel="noopener noreferrer"&gt;http://docs.oasis-open.org/imi/ns/identity-200810&lt;/a&gt;), but there is just plain text. So the &lt;code&gt;ClaimTypes&lt;/code&gt;, can be also customized as you wish.\&lt;br&gt;
The &lt;code&gt;Claims&lt;/code&gt; will be used on the &lt;code&gt;TokenService&lt;/code&gt; to set the Subject, which in fact is the Token Payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#TokenService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;TokenService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;TokenService&lt;/code&gt; is receiving the &lt;code&gt;User&lt;/code&gt; from the &lt;code&gt;AuthenticationService&lt;/code&gt; and uses it to set the Subject (i.e. Payload) of the Token.\&lt;br&gt;
Besides this change, there is only one change that has to be done, on the &lt;code&gt;GetTokenDescriptor&lt;/code&gt; method, when the &lt;code&gt;SecurityTokenDescriptor&lt;/code&gt; is created, the subject is initialized with a new &lt;code&gt;ClaimsIdentity&lt;/code&gt; that gets the user claims.&lt;/p&gt;

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

private SecurityTokenDescriptor GetTokenDescriptor()
{
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(user.Claims()),
        ...
    };

    return tokenDescriptor;
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#UserController" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;UserController&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now that the Claims are set, the &lt;code&gt;UserController&lt;/code&gt; will be the playground for the set claims and roles. In order to accept requests with the created Token, the Controller must have the same Scheme as the Token set on the &lt;code&gt;AuthorizeAttribute&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[Route("identity/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class UserController : ControllerBase
{
    ...
}


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#GetClaims-method" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;GetClaims&lt;/code&gt; method
&lt;/h3&gt;

&lt;p&gt;Firstly the user claims will be getting by using the &lt;code&gt;User&lt;/code&gt; from the base class of the controller (i.e. &lt;code&gt;ControllerBase&lt;/code&gt;), which has the &lt;code&gt;Claims&lt;/code&gt; getter. Because the &lt;code&gt;Claim&lt;/code&gt; class has many properties, that can be found on the Microsoft website: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.claims.claim?view=netcore-3.1" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/system.security.claims.claim?view=netcore-3.1&lt;/a&gt;, for this example just the &lt;code&gt;Type&lt;/code&gt; and the &lt;code&gt;Value&lt;/code&gt; associated with will be used.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{"lastUpload":"2020-06-03T07:43:38.634Z","extensionVersion":"v3.4.3"}


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

&lt;/div&gt;

&lt;p&gt;In the picture below, the claims of the john.doe user are get. We can see that besides the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;role&lt;/code&gt; claims, there are three more which are not added explicitly; but were added by default when the Token was created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-claims.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%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-claims.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;nbf&lt;/code&gt; or Not Before, is used to verify that token will be valid only after it was created and not in the past;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;exp&lt;/code&gt; or Expiration Time, it's self-explanatory and was set because the &lt;code&gt;LifeTimeValidator&lt;/code&gt; was specified when the Token was created;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;iat&lt;/code&gt; or Issued At as previously mentioned, is the time when the Token was created;\
The time represents the seconds in the Unix epoch time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the claims can be found on this scientific paper, which I used as a reference for these articles: &lt;a href="https://tools.ietf.org/html/rfc7519#section-4.1" rel="noopener noreferrer"&gt;https://tools.ietf.org/html/rfc7519#section-4.1&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#GetName" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;GetName&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;GetName&lt;/code&gt; method, the value of &lt;code&gt;Name&lt;/code&gt; claim is get for the given Token, which represents the username. The &lt;code&gt;User&lt;/code&gt; already has predefined methods, like &lt;code&gt;FindFirstValue&lt;/code&gt; in order to expose its property easily.&lt;/p&gt;

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

[HttpGet("name")]
public IActionResult GetName()
{
    string name = User.FindFirstValue(ClaimTypes.Name);
    return Ok(name);
}


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

&lt;/div&gt;

&lt;p&gt;In the response, only the username is returned from the Claim.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-name.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%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-name.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/#GetRoles" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;GetRoles&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;And the last method is using the &lt;code&gt;AuthorizedAttribute&lt;/code&gt; with the &lt;code&gt;Roles&lt;/code&gt; property to give access only to the users that have the set role, in this case, Admin.&lt;/p&gt;

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

[HttpGet("roles")]
[Authorize(Roles = "Admin")]
public IActionResult GetRoles()
{
    IEnumerable&amp;lt;Claim&amp;gt; roleClaims = User.FindAll(ClaimTypes.Role);
    IEnumerable&amp;lt;string&amp;gt; roles = roleClaims.Select(r =&amp;gt; r.Value);
    return Ok(roles);
}


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

&lt;/div&gt;

&lt;p&gt;Let's test with john.doe user, that only have the User role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-roles-forbidden.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%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-roles-forbidden.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The response code is 403 Forbidden because the request didn't pass AuthorizeAttribute`.&lt;/p&gt;

&lt;p&gt;Now, the jane.doe user will be logged in, and we'll try to get her roles with the generated token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-roles-ok.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%2Feduardstefanescu.dev%2F2020%2F05%2F02%2Fjwt-token-claims-in-asp-dotnet-core%2Fjwt-get-roles-ok.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above picture, the response code is OK and its body contains the user roles, as expected because the role is the requested one.&lt;/p&gt;




&lt;p&gt;The source code from this article can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/JwtAuthentication" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/JwtAuthentication&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>asp</category>
      <category>dotnet</category>
      <category>claims</category>
      <category>authorization</category>
    </item>
    <item>
      <title>JWT Authentication with Asymmetric Encryption using certificates in ASP.NET Core</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 11:45:33 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/jwt-authentication-with-asymmetric-encryption-using-certificates-in-asp-net-core-2o7e</link>
      <guid>https://dev.to/eduardstefanescu/jwt-authentication-with-asymmetric-encryption-using-certificates-in-asp-net-core-2o7e</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;In the previous article I wrote about JWT Authentication using a single security key, this being called Symmetric Encryption. The main disadvantage of using this encryption type is that anyone that has access to the key that the token was encrypted with, can also decrypt it. Instead, this article will cover the Asymmetric Encryption for JWT Token.&lt;br&gt;
In the first part of this article, the Asymmetric Encryption concept will be explained, and in the second part, there will be the implementation of the JWT Token-based Authentication using the Asymmetric Encryption approach by creating an "Authentication" Provider in ASP.NET Core.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#Introduction" rel="noopener noreferrer"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;The JWT Token concepts were explained in the previous article, so if you want to find more before continuing reading this article, check out the introduction of the previous one: &lt;a href="https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Introduction" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Introduction&lt;/a&gt;.&lt;br&gt;
Asymmetric Encryption is based on two keys, a public key, and a private key. The public key is used to validate, in this case, the JWT Token. And the private key is used to sign the Token. Maybe the previous statement is a little bit fuzzy, but I hope that will make sense in a moment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fasymmetric-key.svg" 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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fasymmetric-key.svg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For using Asymmetric Encryption, two keys have to be generated, these two keys have to come from the same root. In this case for this article, there will be a certificate - the root - from which the private and the public key will be generated. These keys will be also certificates, so the first thing that has to be done is to generate the private certificate - key - and the second one to generate the public certificate - key - from the private certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#Generating-the-keys" rel="noopener noreferrer"&gt;&lt;/a&gt;Generating the keys
&lt;/h2&gt;

&lt;p&gt;To generate certificates I chose to use the OpenSSL toolkit. If you are on Windows, OpenSSL can be downloaded as an executable and installed where ever you want. I recommend being installed on the C:\ root.&lt;br&gt;
OpenSSL download link: &lt;a href="https://slproweb.com/products/Win32OpenSSL.html" rel="noopener noreferrer"&gt;https://slproweb.com/products/Win32OpenSSL.html&lt;/a&gt;&lt;br&gt;
The tool has to be used from the Terminal, so there are two choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Run the executable from where the tool was installed.&lt;/li&gt;
&lt;li&gt; Add an environment variable to have access to it from everywhere as a CLI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To add the tool as an environment variable the following entry has to be inserted into the User variables:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Variable name: OPENSSL_CONF&lt;br&gt;
  Variable value: &amp;lt;PATH_TO_OPEN_SSL&amp;gt;\bin\cnf\openssl.cnf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After configuring OpenSSL, the private and public key have to be generated using the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For the private key: &lt;code&gt;openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;genpkey&lt;/code&gt; specifying that we'll generate a private key;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;-algorithm RSA&lt;/code&gt; the algorithm used, in this case RSA;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;-out private_key.pem&lt;/code&gt; the output argument and path;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;-pkeyopt rsa_keygen_bits:2048&lt;/code&gt; set the public key algorithm and the key size;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;For the public key: &lt;code&gt;openssl rsa -pubout -in private_key.pem -out public_key.pem&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;rsa&lt;/code&gt; specifying that the command will process RSA keys;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;-pubout -in private_key.pem&lt;/code&gt; the private key and the path of it;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;-out public_key.pem&lt;/code&gt; the output argument and path;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before starting into code, the generated PEM keys have to be converted into XML files. That was the easiest way to read them using the &lt;code&gt;System.Security.Cryptography&lt;/code&gt; package.&lt;br&gt;
To convert them into XML you can use this site: &lt;a href="https://superdry.apphb.com/tools/online-rsa-key-converter" rel="noopener noreferrer"&gt;https://superdry.apphb.com/tools/online-rsa-key-converter&lt;/a&gt;, then copy the converted text into two files with the XML extension in the project folder.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The Setup is the same as in the previous article, so check it out here: &lt;a href="https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Setup" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Setup&lt;/a&gt;. TL;DR you have to install the following package: &lt;code&gt;Microsoft.AspNetCore.Authentication.JwtBearer&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#Startup" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;Startup&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;As in the previous article, the Authentication service has to be added in the &lt;code&gt;ConfigureServices&lt;/code&gt; method from the &lt;code&gt;Startup&lt;/code&gt; class. For Authentication, an extension method called &lt;code&gt;AddAsymmetricAuthentication&lt;/code&gt; will set up the service with the basic settings.&lt;br&gt;
It may be a little bit confusing to switch between this and the previous article, but the only thing that is changed here compared to the previous article is the &lt;code&gt;IssuerSigningKey&lt;/code&gt; property, which now receives the &lt;code&gt;SigningKey&lt;/code&gt;. The previous article contains a comprehensive explanation of each property that it's used: &lt;a href="https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Startup" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Startup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SigningIssuerCertificate&lt;/code&gt; is used to get the &lt;code&gt;IssuerCertificate&lt;/code&gt; or the public key; I will return to this class in a moment. The code below contains only what is necessary to use the public key in the Authentication service.&lt;/p&gt;

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

public static IServiceCollection AddAsymmetricAuthentication(this IServiceCollection services)
{
    var issuerSigningCertificate = new SigningIssuerCertificate();
    RsaSecurityKey issuerSigningKey = issuerSigningCertificate.GetIssuerSigningKey();
    services.AddAuthentication(authOptions =&amp;gt;
        {
          ...
        })
        .AddJwtBearer(options =&amp;gt;
        {
            ...
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ...
                IssuerSigningKey = issuerSigningKey,
                ...
            };
        });

    return services;
}


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

&lt;/div&gt;

&lt;p&gt;After the &lt;code&gt;Authentication&lt;/code&gt; service was added, in the &lt;code&gt;Configure&lt;/code&gt; method the &lt;code&gt;Authorization&lt;/code&gt; and &lt;code&gt;Authentication&lt;/code&gt; middleware needs to be added to the pipeline.&lt;/p&gt;

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

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseAuthentication();
    app.UseAuthorization();
    ...
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#SigningIssuerCertificate" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;SigningIssuerCertificate&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In this class, the RSA class is used to create a &lt;code&gt;RsaSecurityKey&lt;/code&gt; with the public key generated before.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public RsaSecurityKey GetIssuerSigningKey()
{
    string publicXmlKey = File.ReadAllText("./public_key.xml");
    rsa.FromXmlString(publicXmlKey);

    return new RsaSecurityKey(rsa);
}


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;FromXmlString&lt;/code&gt; initializes the &lt;code&gt;rsa&lt;/code&gt; object with parameters from the XML files.&lt;br&gt;
If we dig down in this method - &lt;a href="https://git.io/JvbVm" rel="noopener noreferrer"&gt;https://git.io/JvbVm&lt;/a&gt; - we can see that the &lt;code&gt;RSAParameters&lt;/code&gt; are the same as they are in the XML file converted before.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rsa&lt;/code&gt; is created on the constructor, this object must be disposed because there might be some resources that will run after the process ends.&lt;/p&gt;

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

public void Dispose()
{
    rsa?.Dispose();
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#SigningAudience-Certificate" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;SigningAudience Certificate&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SigningAudienceCertificate&lt;/code&gt; is very similar to the &lt;code&gt;SigningIssuerCertificate&lt;/code&gt;, the only differences are that, is using the private key to initialize the &lt;code&gt;rsa&lt;/code&gt; object and is returning &lt;code&gt;SigningCredentials&lt;/code&gt; constructed with the &lt;code&gt;RsaSecurityKey&lt;/code&gt; and the &lt;code&gt;SecurityAlgorithms&lt;/code&gt;. For this, the &lt;code&gt;RsaSha256&lt;/code&gt; algorithm is used because is the most recommended one. If you want to find what algorithm to use for each type of encryption, check out this article: &lt;a href="https://auth0.com/blog/json-web-token-signing-algorithms-overview/" rel="noopener noreferrer"&gt;https://auth0.com/blog/json-web-token-signing-algorithms-overview/&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public SigningCredentials GetAudienceSigningKey()
{
    string privateXmlKey = File.ReadAllText("./private_key.xml");
    rsa.FromXmlString(privateXmlKey);

    return new SigningCredentials(
        key: new RsaSecurityKey(rsa),
        algorithm: SecurityAlgorithms.RsaSha256);
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#AuthenticationService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;AuthenticationService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This service is used by the &lt;code&gt;AuthenticationController&lt;/code&gt; to authenticate the user. It is like a middleware because it's using the &lt;code&gt;UserService&lt;/code&gt; to validate the received &lt;code&gt;UserCredentials&lt;/code&gt; and the &lt;code&gt;TokenService&lt;/code&gt; to generate the JWT Token if the credentials were valid.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;UserService&lt;/code&gt; and &lt;code&gt;UserCredentials&lt;/code&gt; were created in the previous article so I will use them from there. The &lt;code&gt;UserService&lt;/code&gt; is a more likely a mock service, that has an internal list of users and checks if the given credentials are on that list. And the &lt;code&gt;UserCredentials&lt;/code&gt; contains two properties &lt;code&gt;Username&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public string Authenticate(UserCredentials userCredentials)
{
    userService.ValidateCredentials(userCredentials);
    string securityToken = tokenService.GetToken();

    return securityToken;
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#TokenService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;TokenService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;TokenService&lt;/code&gt; initializes on the constructor the &lt;code&gt;SigningAudienceCertificate&lt;/code&gt; class created before. With this object, the &lt;code&gt;SigningCredentials&lt;/code&gt; for the &lt;code&gt;TokenDescriptor&lt;/code&gt; will be created.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

private readonly SigningAudienceCertificate signingAudienceCertificate;

public TokenService()
{
    signingAudienceCertificate = new SigningAudienceCertificate();
}


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;GetToken&lt;/code&gt; method is used to generate the &lt;code&gt;TokenDescriptor&lt;/code&gt; by using the &lt;code&gt;GetTokenDescriptor&lt;/code&gt; method that will be explained in a moment; to create a &lt;code&gt;SecurityToken&lt;/code&gt; from that descriptor and to get the token as a string from that object.&lt;/p&gt;

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

public string GetToken()
{
    SecurityTokenDescriptor tokenDescriptor = GetTokenDescriptor();
    var tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
    string token = tokenHandler.WriteToken(securityToken);

    return token;
}


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;GetTokenDescriptor&lt;/code&gt; method creates a token with the minimum required properties: &lt;code&gt;Expires&lt;/code&gt; and &lt;code&gt;SigningCredentials&lt;/code&gt;. Also, the &lt;code&gt;Expires&lt;/code&gt; property here is used because on the &lt;code&gt;Authentication&lt;/code&gt; method the &lt;code&gt;LifetimeValidator&lt;/code&gt; was set, but it doesn't need to be specified.&lt;br&gt;
All &lt;code&gt;SecurityTokenDescriptor&lt;/code&gt; properties can be found on the Microsoft website: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.securitytokendescriptor" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.securitytokendescriptor&lt;/a&gt;.&lt;br&gt;
The &lt;code&gt;GetAudienceSigningKey&lt;/code&gt; method created before is used to generate the Token &lt;code&gt;SigningCredentials&lt;/code&gt;, to validate that the Token was signed with the same private key from which the public key was generated.&lt;/p&gt;


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

&lt;p&gt;private SecurityTokenDescriptor GetTokenDescriptor()&lt;br&gt;
{&lt;br&gt;
    const int expiringDays = 7;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var tokenDescriptor = new SecurityTokenDescriptor
{
    Expires = DateTime.UtcNow.AddDays(expiringDays),
    SigningCredentials = signingAudienceCertificate.GetAudienceSigningKey()
};

return tokenDescriptor;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#AuthenticationController" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;AuthenticationController&lt;/code&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;AuthenticationController&lt;/code&gt; an endpoint is created to authenticate the user with &lt;code&gt;UserCredentials&lt;/code&gt; and get the JWT Token by using the &lt;code&gt;AuthenticationService&lt;/code&gt; described earlier.&lt;/p&gt;


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

&lt;p&gt;[HttpPost]&lt;br&gt;
public IActionResult Authenticate([FromBody] UserCredentials userCredentials)&lt;br&gt;
{&lt;br&gt;
    try&lt;br&gt;
    {&lt;br&gt;
        string token = authenticationService.Authenticate(userCredentials);&lt;br&gt;
        return Ok(token);&lt;br&gt;
    }&lt;br&gt;
    catch (InvalidCredentialsException)&lt;br&gt;
    {&lt;br&gt;
        return Unauthorized();&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#ValidationController" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;ValidationController&lt;/code&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;And the &lt;code&gt;ValidationController&lt;/code&gt; contains a plain endpoint that it's using the &lt;code&gt;Authorize&lt;/code&gt; attribute to validate the Token. Note that the Authentication Scheme must be used on the Authorize attribute and for the Authentication service.&lt;/p&gt;


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

&lt;p&gt;[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]&lt;br&gt;
public IActionResult Validate()&lt;br&gt;
{&lt;br&gt;
    return Ok();&lt;br&gt;
}&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#The-result" rel="noopener noreferrer"&gt;&lt;/a&gt;The result&lt;br&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#Authentication" rel="noopener noreferrer"&gt;&lt;/a&gt;Authentication
&lt;/h3&gt;

&lt;p&gt;Firstly the Authentication happy flow will be tested, so the combination of the username and password will match and the endpoint should provide the generated Token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fauthorized-authentication.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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fauthorized-authentication.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And secondly let's test the unauthorized flow, where the provided credentials are wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Funauthorized-authentication.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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Funauthorized-authentication.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/#Validation" rel="noopener noreferrer"&gt;&lt;/a&gt;Validation
&lt;/h3&gt;

&lt;p&gt;Before checking that the Token is valid using the &lt;code&gt;ValidationController&lt;/code&gt;, Auth0 crafted &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;https://jwt.io/&lt;/a&gt; that decode the Token and check whether or not the Token is valid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fjwt-token-validation.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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fjwt-token-validation.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the Verify Signature section, both keys must be entered to validate the signature of the certificate.&lt;br&gt;
Now the &lt;code&gt;ValidationController&lt;/code&gt; will be used to check whether the token is valid or not, but this will happen internally, on the Authorize attribute. Firstly, the happy flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fvalid-token.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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Fvalid-token.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And in the second test, the wrong token is validated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Finvalid-token.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%2Feduardstefanescu.dev%2F2020%2F04%2F25%2Fjwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core%2Finvalid-token.png"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The source code from this article can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/JwtAuthentication" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/JwtAuthentication&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>asp</category>
      <category>dotnet</category>
      <category>authentication</category>
      <category>encryption</category>
    </item>
    <item>
      <title>JWT Authentication with Symmetric Encryption in ASP.NET Core</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 11:37:50 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/jwt-authentication-with-symmetric-encryption-in-asp-net-core-2i53</link>
      <guid>https://dev.to/eduardstefanescu/jwt-authentication-with-symmetric-encryption-in-asp-net-core-2i53</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;JWT Authentication is becoming one of the most used authentication types in modern web applications or services. This article covers the JWT Authentication with a Symmetric Key in ASP.NET Core. In the first part, there will be a short introduction to what Symmetric Key represents and the second part contains the prerequisites for this project and the actual implementation of this authentication type.&lt;br&gt;
This article is the first article from of series of two, the second one will contain the authentication with an Asymmetric Key using a certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Introduction" rel="noopener noreferrer"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;JWT Token is a common way of creating access tokens that can contain several claims (e.g. Username, Roles). JWT Token means JSON (JavaScript Object Notation) Web Token. Every JWT Token has the following structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Header, containing the encryption algorithm;&lt;/li&gt;
&lt;li&gt;  Payload, containing custom Claims, plus at least two required claims:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;exp&lt;/code&gt; representing the expiration time when the Token will become unavailable;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;iat&lt;/code&gt; or Issued at Time, the time when the Token was created;\
The times are formatted using the Unix Timestamp format (e.g. 1582784721).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Signature, representing the encoded header, plus &lt;code&gt;a dot&lt;/code&gt;, plus the encoded payload, plus a secret key. The concatenated result will be run through the encryption algorithm specified on the Header to validate the Token.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you want to read more about JWT Token, this comprehensive paper covers all the concepts: &lt;a href="https://tools.ietf.org/html/rfc7519" rel="noopener noreferrer"&gt;https://tools.ietf.org/html/rfc7519&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Symmetric-Key" rel="noopener noreferrer"&gt;&lt;/a&gt;Symmetric Key
&lt;/h3&gt;

&lt;p&gt;The Symmetric Key is used both for signing and validation. For example, let's say John wants to share a secret with Jane, when the secret is told, John also tells Jane a password - the key - in order for the secret to being understood. In this way, John - the identity provider or the service - ensures that his secret is well kept by using the given password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fsymmetric-key.svg" 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%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fsymmetric-key.svg" alt="Symmetric Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Setup" rel="noopener noreferrer"&gt;&lt;/a&gt;Setup
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core 3.1 will be used for this project. Microsoft also offers a great package that provides all that is needed to create a JWT Token-based authentication. The package is called &lt;code&gt;Microsoft.AspNetCore.Authentication.JwtBearer&lt;/code&gt;, this is the only package that the project needs, and can be found here: &lt;a href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Creating-a-secret-key" rel="noopener noreferrer"&gt;&lt;/a&gt;Creating a secret key
&lt;/h2&gt;

&lt;p&gt;The signing and validation key will be a user secret key. ASP.NET provides the user secret key feature to store all the confidential data that doesn't have to be committed or shared outside the user or developer environment. For the production or testing environments, the keys need to be store in a cloud vault, like Microsoft Azure offers through Key Vault - &lt;a href="https://azure.microsoft.com/en-us/services/key-vault/" rel="noopener noreferrer"&gt;https://azure.microsoft.com/en-us/services/key-vault/&lt;/a&gt; -, but this will be a topic for another article.\&lt;br&gt;
Firstly, the project needs to be initiated for using user secrets, by running the following command in the project folder:&lt;/p&gt;

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

dotnet user-secrets init


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

&lt;/div&gt;

&lt;p&gt;Then the user secret key is added, using the following command:&lt;/p&gt;

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

dotnet user-secrets set "AppSettings:EncryptionKey" "POWERFULENCRYPTIONKEY"


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

&lt;/div&gt;

&lt;p&gt;This command will add to the &lt;code&gt;secrets.json&lt;/code&gt; file the &lt;code&gt;AppSettings:EncryptionKey&lt;/code&gt; key with the value &lt;code&gt;POWERFULENCRYPTIONKEY&lt;/code&gt;.\&lt;br&gt;
If there are multiple values for the &lt;code&gt;AppSettings&lt;/code&gt; then this key can become more readable by using a JSON format like:&lt;/p&gt;

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

"AppSettings": {
  "EncryptionKey": "POWERFULENCRYPTIONKEY",
  "Key2": "Value2" 
} 


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;POWERFULENCRYPTIONKEY&lt;/code&gt; will be encoded in an array of bytes and then this binary will be Base64 encoded, this is required for both signing and validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#Startup" rel="noopener noreferrer"&gt;&lt;/a&gt;Startup
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;ConfigureServices&lt;/code&gt; method from the &lt;code&gt;Startup&lt;/code&gt; class, the &lt;code&gt;AppSettings&lt;/code&gt; section needs to be read. To read a type from the configuration file, a class must be created, so for the &lt;code&gt;AppSettings&lt;/code&gt; section an equivalent class needs to exists, as is shown below. This class can be seen as a Data Transfer Object, which contains plain properties.&lt;/p&gt;

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

public class AppSettings
{
    public string EncryptionKey { get; set; }
}


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

&lt;/div&gt;

&lt;p&gt;After the section is read, the &lt;code&gt;EncryptionKey&lt;/code&gt; needs to be converted into bytes.&lt;/p&gt;

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

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    IConfigurationSection settingsSection = configuration.GetSection("AppSettings");
    AppSettings settings = settingsSection.Get&amp;lt;AppSettings&amp;gt;();
    byte[] signingKey = Encoding.UTF8.GetBytes(settings.EncryptionKey);

    services.AddAuthentication(signingKey);

    services.Configure&amp;lt;AppSettings&amp;gt;(settingsSection);
    services.AddTransient&amp;lt;AuthenticationService&amp;gt;();
    services.AddTransient&amp;lt;UserService&amp;gt;();
    services.AddTransient&amp;lt;TokenService&amp;gt;();
}


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

&lt;/div&gt;

&lt;p&gt;On &lt;code&gt;line 9&lt;/code&gt; the &lt;code&gt;Authentication&lt;/code&gt; service is added into the App container, this service is responsible, for managing &lt;code&gt;Authentication&lt;/code&gt; settings, like &lt;code&gt;IssuerSigningKey&lt;/code&gt; or &lt;code&gt;LifeTimeValidation&lt;/code&gt;.\&lt;br&gt;
For this step, an extension method is created called &lt;code&gt;AddAuthentication&lt;/code&gt;, which receives the &lt;code&gt;service&lt;/code&gt; and the &lt;code&gt;signingKey&lt;/code&gt; converted earlier.\&lt;br&gt;
From &lt;code&gt;line 11&lt;/code&gt; to &lt;code&gt;14&lt;/code&gt;, the services are configured for the Dependency Injection, we will return to the implementation of these services in a moment.&lt;/p&gt;

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

public static IServiceCollection AddAuthentication(this IServiceCollection services,
    byte[] signingKey)
{
    services.AddAuthentication(authOptions =&amp;gt;
        {
            authOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            authOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(jwtOptions =&amp;gt;
        {
            jwtOptions.SaveToken = true;
            jwtOptions.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(signingKey),
                ValidateLifetime = true,
                LifetimeValidator = LifetimeValidator
            };
        });

    return services;
}


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;authenticationOptions&lt;/code&gt; need to configure the &lt;code&gt;Authenticate&lt;/code&gt; and &lt;code&gt;Challenge&lt;/code&gt; Schemes, in order to verify that the endpoint(s) which receives a JWT Token will go through the validation step, as is described below starting from &lt;code&gt;line 12&lt;/code&gt;. The same Schema will be seen on the endpoints that use the &lt;code&gt;AuthorizeAttribute&lt;/code&gt;.\&lt;br&gt;
Then the &lt;code&gt;JwtBearer&lt;/code&gt; is added to the &lt;code&gt;Authentication&lt;/code&gt; process, using the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;SaveToken&lt;/code&gt; is self-explanatory. It's used to persist the Token into local storage. The token will be valid even if the service restarts, so its lifetime is different from the application;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ValidateAudience&lt;/code&gt; and &lt;code&gt;ValidateIssuer&lt;/code&gt; must be used for the service to skip or to validate the Audience or the Issuer. The Audience refers to the server or the Identity Provider, in this case, our ASP.NET Service. And the &lt;code&gt;Issuer&lt;/code&gt; refers to the client(s) that makes HTTP request(s). For the sake of this example, both are set &lt;code&gt;false&lt;/code&gt;. Please note that even if you don't want to validate the &lt;code&gt;Audience&lt;/code&gt; or/and the &lt;code&gt;Issuer&lt;/code&gt; these values must be set;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ValidateIssuerSigningKey&lt;/code&gt; needs to be set to &lt;code&gt;true&lt;/code&gt;, in order to validate the received Token;&lt;/li&gt;
&lt;li&gt;  For &lt;code&gt;IssuerSigningKey&lt;/code&gt; will use the &lt;code&gt;SymmetricSecurityKey&lt;/code&gt;, the same approach will be also used when the Token will be created.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;LifeTimeValidator&lt;/code&gt; is important if the generated &lt;code&gt;Token&lt;/code&gt; has set an expiration time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the JWT Bearer Options can be found on the Microsoft website: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbeareroptions" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbeareroptions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LifeTimeValidator&lt;/code&gt; handler is checking if the expiration date is greater than the current Date, as follows:&lt;/p&gt;

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

private static bool LifetimeValidator(DateTime? notBefore,
    DateTime? expires,
    SecurityToken securityToken,
    TokenValidationParameters validationParameters)
{
    return expires != null &amp;amp;&amp;amp; expires &amp;gt; DateTime.Now;
}


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

&lt;/div&gt;

&lt;p&gt;After the services were configured, the &lt;code&gt;Authentication&lt;/code&gt; and &lt;code&gt;Authorization&lt;/code&gt; middleware must be added to the App pipeline in the &lt;code&gt;Configure&lt;/code&gt; method.&lt;/p&gt;

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

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseAuthentication();
    app.UseAuthorization();
    ...
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#UserCredentials" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;UserCredentials&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;User's Credentials will be used as a Data Transfer Object, this class will be received on the authentication endpoint and sent to the &lt;code&gt;AuthenticationService&lt;/code&gt;. It's a plain class that contains only the &lt;code&gt;Username&lt;/code&gt; and the &lt;code&gt;Password&lt;/code&gt; of the user.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public class UserCredentials
{
    public string Username { get; set; }
    public string Password { get; set; }
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#AuthenticationService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;AuthenticationService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AuthenticationService&lt;/code&gt; is used like a middleware that receives the &lt;code&gt;UserCredentials&lt;/code&gt; from the &lt;code&gt;Controller&lt;/code&gt;, validates them using the &lt;code&gt;UserService&lt;/code&gt; and if the credentials are valid, it creates a Token using the &lt;code&gt;TokenService&lt;/code&gt;. Both the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Token&lt;/code&gt; services are injected into the constructor.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public string Authenticate(UserCredentials userCredentials)
{
    userService.ValidateCredentials(userCredentials);
    string securityToken = tokenService.GetToken();

    return securityToken;
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#UserService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;UserService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For the sake of this example, the &lt;code&gt;UserService&lt;/code&gt; contains a list of users created on the constructor. In a real-life scenario, this will be read from storage or from a service.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public class UserService
{
    private readonly IEnumerable&amp;lt;UserCredentials&amp;gt; users;

    public UserService()
    {
        users = new List&amp;lt;UserCredentials&amp;gt;
        {
            new UserCredentials
            {
                Username = "john.doe",
                Password = "john.password"
            }
        };
    }
...


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

&lt;/div&gt;

&lt;p&gt;This is more like a &lt;code&gt;UserValidation&lt;/code&gt; service, but to better illustrate that it also reads the users, the &lt;code&gt;UserService&lt;/code&gt; name will be kept.&lt;/p&gt;

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

...
    public void ValidateCredentials(UserCredentials userCredentials)
    {
        bool isValid =
            users.Any(u =&amp;gt;
                u.Username == userCredentials.Username &amp;amp;&amp;amp;
                u.Password == userCredentials.Password);

        if (!isValid)
        {
            throw new InvalidCredentialsException();
        }
    }
}


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;ValidateCredentials&lt;/code&gt; method checks if the &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; pair exists, and if it doesn't it will throw the &lt;code&gt;InvalidCredentialsException&lt;/code&gt; which will be caught on the &lt;code&gt;Controller&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#TokenService" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;TokenService&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;TokenService&lt;/code&gt; is receiving on the constructor the &lt;code&gt;AppSettings&lt;/code&gt;, which will be used on the &lt;code&gt;GetTokenDescriptor&lt;/code&gt; method to set up the Token.&lt;/p&gt;

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

public class TokenService
{
    private readonly AppSettings appSettings;

    public TokenService(IOptions&amp;lt;AppSettings&amp;gt; options)
    {
        appSettings = options.Value;
    }
...


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

&lt;/div&gt;

&lt;p&gt;The public &lt;code&gt;GetToken&lt;/code&gt; method is used to get the token description, to create the Token and write it into a string, that will be returned to the calling service, in this case to the &lt;code&gt;AuthenticationService&lt;/code&gt;.&lt;/p&gt;

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

public string GetToken()
{
    SecurityTokenDescriptor tokenDescriptor = GetTokenDescriptor();
    var tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
    string token = tokenHandler.WriteToken(securityToken);

    return token;
}


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

&lt;/div&gt;

&lt;p&gt;On the &lt;code&gt;GetTokenDescriptor&lt;/code&gt; method, the token is constructed. In this method, the &lt;code&gt;ExpirationTime&lt;/code&gt; and &lt;code&gt;SigningCredentials&lt;/code&gt; are set. Because the Claims are not in the main focus of this article, I will create another one, in which I will explain how the Claims can be set on the Token and how they can be used.&lt;/p&gt;

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

private SecurityTokenDescriptor GetTokenDescriptor()
{
    const int expiringDays = 7;

    byte[] securityKey = Encoding.UTF8.GetBytes(appSettings.EncryptionKey);
    var symmetricSecurityKey = new SymmetricSecurityKey(securityKey);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Expires = DateTime.UtcNow.AddDays(expiringDays),
        SigningCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature)
    };

    return tokenDescriptor;
}


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

&lt;/div&gt;

&lt;p&gt;All the Token Descriptors can be found on the Microsoft website: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.securitytokendescriptor" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.securitytokendescriptor&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#AuthenticationController" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;AuthenticationController&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now, all we have to do, is to create an &lt;code&gt;AuthenticationController&lt;/code&gt; which receives the &lt;code&gt;UserCredentials&lt;/code&gt; and uses the previously created &lt;code&gt;AuthenticationService&lt;/code&gt;.\&lt;br&gt;
On the constructor the &lt;code&gt;AuthenticationService&lt;/code&gt; is injected, to be used on the &lt;code&gt;Authentication&lt;/code&gt; endpoint.&lt;/p&gt;

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

[Route("identity/[controller]")]
public class AuthenticationController : ControllerBase
{
    private readonly AuthenticationService authenticationService;

    public AuthenticationController(AuthenticationService authenticationService)
    {
        this.authenticationService = authenticationService;
    }
...


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

&lt;/div&gt;

&lt;p&gt;The authentication endpoint accepts HTTP Post requests, receives the &lt;code&gt;UserCredentials&lt;/code&gt; as previously mentioned, and uses the &lt;code&gt;AuthenticationService&lt;/code&gt; to authenticate and create the Token.&lt;/p&gt;

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

...
    [HttpPost]
    public IActionResult Authenticate([FromBody] UserCredentials userCredentials)
    {
        try
        {
            string token = authenticationService.Authenticate(userCredentials);
            return Ok(token);
        }
        catch (InvalidCredentialsException)
        {
            return Unauthorized();
        }
    }
}


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

&lt;/div&gt;

&lt;p&gt;If the credentials are valid, then the endpoint will return an &lt;code&gt;OK&lt;/code&gt; HTTP Status code and the generated token. Otherwise, if the &lt;code&gt;InvalidCredentialsException&lt;/code&gt; is thrown, the &lt;code&gt;Unauthorized&lt;/code&gt; HTTP Status code is returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#ValidationController" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;ValidationController&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The purpose of the &lt;code&gt;ValidationController&lt;/code&gt; is to check that the signing process is working, in order to validate the Token.&lt;/p&gt;

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

Route("identity/[controller]")]
public class ValidationController : ControllerBase
{
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public IActionResult Validate()
    {
        return Ok();
    }
}


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

&lt;/div&gt;

&lt;p&gt;You may notice that the &lt;code&gt;Validate&lt;/code&gt; endpoint has the &lt;code&gt;AuthorizeAttribute&lt;/code&gt; which has on its constructor the same &lt;code&gt;AuthenticationSchemes&lt;/code&gt; as was set on the &lt;code&gt;Authentication&lt;/code&gt; service.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/#The-result" rel="noopener noreferrer"&gt;&lt;/a&gt;The result
&lt;/h2&gt;

&lt;p&gt;Firstly, the happy flow for the &lt;code&gt;AuthenticationController&lt;/code&gt; is tested, so we'll provide the correct combination of the username and password, in order to receive the token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fhappy-flow-authentication.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%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fhappy-flow-authentication.png" alt="Happy flow authentication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's test with credentials that are not correct, the response should be Unauthorized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Funauthorized-authentication.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%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Funauthorized-authentication.png" alt="Unauthorized authentication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And secondly, the generated token needs to be tested using the &lt;code&gt;Validation&lt;/code&gt; controller. The first test will be with the generated token, to see that the validation is passed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fhappy-flow-validation.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%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Fhappy-flow-validation.png" alt="Happy flow validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the second test is when the wrong token is provided for validation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Funauthorized-validation.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%2Feduardstefanescu.dev%2F2020%2F04%2F11%2Fjwt-authentication-with-symmetric-encryption-in-asp-dotnet-core%2Funauthorized-validation.png" alt="Unauthorized flow validation"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The source code from this article can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/JwtAuthentication" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/JwtAuthentication&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>asp</category>
      <category>dotnet</category>
      <category>encryption</category>
    </item>
    <item>
      <title>RabbitMQ Consumer Received Event with Docker in .NET</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 11:30:02 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/rabbitmq-consumer-received-event-with-docker-in-net-2oid</link>
      <guid>https://dev.to/eduardstefanescu/rabbitmq-consumer-received-event-with-docker-in-net-2oid</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This article contains another approach to consuming messages. The first part will be a comparison between the several types of consuming messages and in the second part, each line of code will be explained.\&lt;br&gt;
The entire environment setup with Docker can be found in the first article from the RabbitMQ series. This series, there are also explained some core principles about each RabbitMQ node. I highly recommend that, if you are at the beginning with RabbitMQ or with the AMQP standard, to start with these articles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/03/07/rabbitmq-exchange-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/03/07/rabbitmq-exchange-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Introduction" rel="noopener noreferrer"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;The RabbitMQ Client provides a &lt;code&gt;Received&lt;/code&gt; event that will be used to consume the messages coming from one or more &lt;code&gt;Queues&lt;/code&gt;. In the &lt;code&gt;Consumer&lt;/code&gt; article, the messages are consumed and acknowledged using the &lt;code&gt;BasicGet&lt;/code&gt; and the &lt;code&gt;BackAck&lt;/code&gt; methods in a while loop, waiting for the &lt;code&gt;CancellationToken&lt;/code&gt;. The advantage of that method is that a message can be consumed when needed. So, care must be taken when using this method. It's not recommended to use it in an infinite while loop if the &lt;code&gt;Received&lt;/code&gt; event exists, and it's a good replacement for that type of approach.\&lt;br&gt;
The advantage of the &lt;code&gt;Received&lt;/code&gt; event is obvious, that will no longer consume unnecessary resources, but the "disadvantage" is that the messages will be consumed whenever they are raised based on the &lt;code&gt;routing key&lt;/code&gt;.\&lt;br&gt;
But this depends on the different scenarios which way to choose. A useful tip that may help when you must choose between these two ways of consuming messages is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;BasicGet&lt;/code&gt; method can be used when there are more messages to get or it needs to be consumed at a certain time;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Received&lt;/code&gt; event can be used when the raised message needs to be consumed immediately;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also another approach to consume messages, by inheriting the &lt;code&gt;DefaultBasicConsumer&lt;/code&gt; class. This gives the advantage of having a hierarchy of consumers, which may lead to different design patterns.&lt;/p&gt;

&lt;p&gt;In the following part of this article, there will be only some chunks of code, which are required to consume the messages using the &lt;code&gt;Received&lt;/code&gt; event. The connection setup is the same as in previous articles.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Received-event" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;Received&lt;/code&gt; event
&lt;/h2&gt;

&lt;p&gt;Before start establishing the connection, a &lt;code&gt;CancellationToken&lt;/code&gt; is needed to wait for the user to stop the Console App execution.&lt;/p&gt;

&lt;p&gt;To bind the &lt;code&gt;Consumer&lt;/code&gt; to the &lt;code&gt;Channel&lt;/code&gt;, a new &lt;code&gt;EventingBasicConsumer&lt;/code&gt; instance is made by passing the &lt;code&gt;Channel&lt;/code&gt; as a parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IConnection connection = factory.CreateConnection();
IModel channel = connection.CreateModel();
var basicConsumer = new EventingBasicConsumer(channel);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An important note here is that there is no need to surround the &lt;code&gt;IConnection&lt;/code&gt; and the &lt;code&gt;IChannel&lt;/code&gt; into a using statement, the reason for this is that the &lt;code&gt;Connection&lt;/code&gt; and the &lt;code&gt;Channel&lt;/code&gt; need to exist as long as the app. If these two variables were disposed too early, then no message would be received.\&lt;br&gt;
You may notice that in this RabbitMQ series, I used the &lt;code&gt;Channel&lt;/code&gt; word instead of the official name &lt;code&gt;Model&lt;/code&gt;, that's because it's easier to understand. For me, a &lt;code&gt;Model&lt;/code&gt; is too generic, instead, a &lt;code&gt;Channel&lt;/code&gt; makes me think of a communication channel, which in fact it really is.\&lt;br&gt;
The official documentation for &lt;code&gt;EventingBasicConsumer&lt;/code&gt; can be found here: &lt;a href="https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.1.1/rabbitmq-dotnet-client-3.1.1-client-htmldoc/html/type-RabbitMQ.Client.Events.EventingBasicConsumer.html" rel="noopener noreferrer"&gt;https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.1.1/rabbitmq-dotnet-client-3.1.1-client-htmldoc/html/type-RabbitMQ.Client.Events.EventingBasicConsumer.html&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Subscribing-to-the-event" rel="noopener noreferrer"&gt;&lt;/a&gt;Subscribing to the event
&lt;/h3&gt;

&lt;p&gt;Using the &lt;code&gt;Consumer&lt;/code&gt; created earlier, we subscribe to the &lt;code&gt;Received&lt;/code&gt; event the &lt;code&gt;OnNewMessageReceived&lt;/code&gt; handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;basicConsumer.Received += OnNewMessageReceived;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Handling-the-event" rel="noopener noreferrer"&gt;&lt;/a&gt;Handling the event
&lt;/h3&gt;

&lt;p&gt;This event handler will display the received message and another message to inform the user that can stop consuming messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void OnNewMessageReceived(object sender, BasicDeliverEventArgs e)
{
    Console.WriteLine($"Message: {Encoding.UTF8.GetString(e.Body)}");
    Console.WriteLine("Press any key to stop consuming message.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Consuming-messages" rel="noopener noreferrer"&gt;&lt;/a&gt;Consuming messages
&lt;/h3&gt;

&lt;p&gt;To start consuming messages, the &lt;code&gt;Consumer&lt;/code&gt; will be bind to the queue. In the following code, there is an iteration through the queues count entered previously. Then the user is asked to enter the &lt;code&gt;Queue&lt;/code&gt; name that will be bound to the &lt;code&gt;Consumer&lt;/code&gt;.\&lt;br&gt;
The &lt;code&gt;BasicConsume&lt;/code&gt; method takes three parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  the first one is the &lt;code&gt;Queue&lt;/code&gt; name;&lt;/li&gt;
&lt;li&gt;  the second is used for auto acknowledgment, in this case, is set to &lt;code&gt;true&lt;/code&gt;, but if it was set to &lt;code&gt;false&lt;/code&gt; then the acknowledgment had to be done manually if this is wanted;&lt;/li&gt;
&lt;li&gt;  and the third one is the &lt;code&gt;Consumer&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Waiting-for-Cancellation" rel="noopener noreferrer"&gt;&lt;/a&gt;Waiting for &lt;code&gt;Cancellation&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;WaitHandle&lt;/code&gt; static class is a handy way to wait for the &lt;code&gt;CancellationToken&lt;/code&gt; to be raised. Instead of the &lt;code&gt;CancellationToken&lt;/code&gt;, the &lt;code&gt;AutoResetEvent&lt;/code&gt; or other signaling events can be also used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WaitHandle.WaitAny(new[] { cancellationToken.WaitHandle });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#Disposing-resources" rel="noopener noreferrer"&gt;&lt;/a&gt;Disposing resources
&lt;/h3&gt;

&lt;p&gt;After the user indicates that no longer wants to receive messages, or in a real-life scenario, when the application ends, all the created resources need to be disposed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;basicConsumer.Received -= OnNewMessageReceived;
channel.Close();
channel.Dispose();
connection.Close();
connection.Dispose();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firstly the &lt;code&gt;OnNewMessageReceived&lt;/code&gt; event handler needs to be unsubscribed from the &lt;code&gt;Received&lt;/code&gt; to stop displaying messages after the program finishes its execution. It can be possible that reference to event handler can still exist after the resources are disposed and the program closes. So, I highly recommend that all the time when it's needed, unsubscribe the event handlers.\&lt;br&gt;
After that, the &lt;code&gt;Channel&lt;/code&gt; and the &lt;code&gt;Connection&lt;/code&gt; are closed and disposed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/04/04/rabbitmq-consumer-events-with-docker-in-dotnet/#The-result" rel="noopener noreferrer"&gt;&lt;/a&gt;The result
&lt;/h3&gt;

&lt;p&gt;Using the &lt;code&gt;Producer&lt;/code&gt;, the direct &lt;code&gt;Exchange&lt;/code&gt; and one &lt;code&gt;Queue&lt;/code&gt; created in the previous articles, the topology will be created and the &lt;code&gt;Consumer&lt;/code&gt; will be connected to it.\&lt;br&gt;
In the picture below, the sent message by the &lt;code&gt;Producer&lt;/code&gt; using a specific &lt;code&gt;routing key&lt;/code&gt; bound to the &lt;code&gt;Queue&lt;/code&gt; reached the event handler, and this displayed the message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F04%2F04%2Frabbitmq-consumer-events-with-docker-in-dotnet%2Fconsumer-received-message.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%2Feduardstefanescu.dev%2F2020%2F04%2F04%2Frabbitmq-consumer-events-with-docker-in-dotnet%2Fconsumer-received-message.png" alt="Consumer received message"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;All the code for this &lt;code&gt;Consumer&lt;/code&gt; and for the entire topology is available on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/RabbitMQ_POC" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/RabbitMQ_POC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>amqp</category>
      <category>docker</category>
      <category>rabbitmq</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>RabbitMQ Headers Exchange with Docker in .NET</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 10:06:05 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/rabbitmq-headers-exchange-with-docker-in-net-3m49</link>
      <guid>https://dev.to/eduardstefanescu/rabbitmq-headers-exchange-with-docker-in-net-3m49</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/"&gt;https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This article is about &lt;code&gt;Headers Exchange&lt;/code&gt;, I chose to create an article just for this type of &lt;code&gt;Exchange&lt;/code&gt; because it needs a little more attention compared to the other three types (i.e. fanout, direct, topic).\&lt;br&gt;
In this article, I will use the setup environment with Docker from the first article, so if you want a good starting point, you can begin with the first article: &lt;a href="https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/"&gt;https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/#Introduction"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Headers Exchange&lt;/code&gt; is routing the messages based on the bindings that are applied to the &lt;code&gt;Producer&lt;/code&gt; and &lt;code&gt;Queue&lt;/code&gt;.\&lt;br&gt;
In order to produce a message, that message should be published with defined properties that are also bound to the &lt;code&gt;Queue&lt;/code&gt; - this is why it's called &lt;code&gt;Headers Exchange&lt;/code&gt; - and can also be seen as the &lt;code&gt;routing key&lt;/code&gt;.\&lt;br&gt;
Another mandatory property that must be bound to the &lt;code&gt;Queue&lt;/code&gt; is &lt;code&gt;x-match&lt;/code&gt;. This property specifies the matching criteria, as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;x-match=all&lt;/code&gt; means that all the header pairs must match;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;x-match=any&lt;/code&gt; means that at least one header pairs must match;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick example, that will be also implemented using .NET Core:\&lt;br&gt;
Let's say that a Windows Application produces two logging types, information and error, and the server process these log messages based on its types.\&lt;br&gt;
So for each log type, will be a &lt;code&gt;Queue&lt;/code&gt; that will have a property &lt;code&gt;log-level&lt;/code&gt; equals to the type of logging that will receive. To send log information, the &lt;code&gt;Producer&lt;/code&gt; must set to that message a property &lt;code&gt;log-level=information&lt;/code&gt; so that the &lt;code&gt;Exchange&lt;/code&gt; will forward the message to the correct &lt;code&gt;Queue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If this is still unclear, then a brief explanation for &lt;code&gt;Headers Exchange&lt;/code&gt; is that the messages contain a header in order to be bound correctly.\&lt;br&gt;
I hope now the whole typology is a little bit clearer, and why this type of &lt;code&gt;Exchange&lt;/code&gt; is called &lt;code&gt;Headers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can start implementing these concepts, the following part will contain code chunks that are required in order to use &lt;code&gt;Headers Exchange&lt;/code&gt;, these chunks were applied to existing code from the previous four articles about RabbitMQ.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/#Producer"&gt;&lt;/a&gt;&lt;code&gt;Producer&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To bind the logging type to the &lt;code&gt;Producer&lt;/code&gt; properties, a &lt;code&gt;Dictionary&lt;/code&gt; of type &lt;code&gt;string, object&lt;/code&gt; is used as the properties headers. In this case, the &lt;code&gt;key&lt;/code&gt; will be &lt;code&gt;log-level&lt;/code&gt; and the &lt;code&gt;value&lt;/code&gt; will be the actual log level (i.e. information or error). For this scenario, the log level is entered by the user, but in a real-life scenario, there will be a logging system that will serve this scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Console.Write("Log level: ");
string logLevel = Console.ReadLine();

Console.Write("Message: ");
string message = Console.ReadLine();

var propertiesHeaders = new Dictionary&amp;lt;string, object&amp;gt; { { "log-level", logLevel } };

using (IConnection connection = factory.CreateConnection())
{
    using (IModel channel = connection.CreateModel())
    {
        IBasicProperties properties = channel.CreateBasicProperties();
        properties.Headers = propertiesHeaders;

        byte[] messageBytes = Encoding.UTF8.GetBytes(message);
        const string exchangeName = "test-exchange";

        channel.BasicPublish(exchangeName, string.Empty, properties, messageBytes);
        Console.WriteLine($"Published message: {message}");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;propertiesHeaders&lt;/code&gt; are bound to the published message by firstly creating plain properties with an empty content header using the &lt;code&gt;CreateBasicProperties&lt;/code&gt; method. The difference between this &lt;code&gt;Producer&lt;/code&gt; and the one from the first article is on line 14, which sets the &lt;code&gt;Headers&lt;/code&gt; property to the dictionary created earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/#Exchange"&gt;&lt;/a&gt;&lt;code&gt;Exchange&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This type of &lt;code&gt;Exchange&lt;/code&gt; is very similar to the one created in the second article. The only thing that changes is the type, which will be set to &lt;code&gt;headers&lt;/code&gt; when the &lt;code&gt;Exchange&lt;/code&gt; is declared on line 7.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using (IConnection connection = factory.CreateConnection())
{
    using (IModel channel = connection.CreateModel())
    {
        const string exchangeName = "test-exchange";
        channel.ExchangeDelete(exchange: exchangeName);
        channel.ExchangeDeclare(exchange: exchangeName, type: "headers");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see this result also on the RabbitMQ Management page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MqGXixnj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/rabbitmq-management-exchange.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MqGXixnj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/rabbitmq-management-exchange.png" alt="RabbitMQ Management Exchange"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/#Queue"&gt;&lt;/a&gt;&lt;code&gt;Queue&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To bound the &lt;code&gt;Queue&lt;/code&gt;, the properties of the header must be set using a &lt;code&gt;Dictionary&lt;/code&gt; of type &lt;code&gt;string, string&lt;/code&gt; that will be passed as arguments to the &lt;code&gt;QueueBind&lt;/code&gt; method.\&lt;br&gt;
For this article, I chose to use the &lt;code&gt;all&lt;/code&gt; value for the first &lt;code&gt;x-match&lt;/code&gt; property, but this value can be also set to &lt;code&gt;any&lt;/code&gt; because only the &lt;code&gt;log-level&lt;/code&gt; header needs to match.\&lt;br&gt;
And the second property is the &lt;code&gt;log-level&lt;/code&gt;, the value of this property is given by the user, but in a real-life scenario, this property will be set by the listener service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Console.Write($"Log level for Queue[{queueIndex}]: ");
var logLevel = Console.ReadLine();

using (IConnection connection = factory.CreateConnection())
{
    using (IModel channel = connection.CreateModel())
    {
        channel.QueueDelete(queue: queueName);

        channel.QueueDeclare(queue: queueName,
            durable: false,
            exclusive: false,
            autoDelete: false,
            arguments: null);

        channel.QueueBind(queue: queueName,
            exchange: "test-exchange",
            routingKey: string.Empty,
            arguments: new Dictionary&amp;lt;string, object&amp;gt;
                {{"x-match", "all"}, {"log-level", logLevel}});
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a &lt;code&gt;Queue&lt;/code&gt; is created the result can be also seen on the RabbitMQ Management page. In the picture below, there is an &lt;code&gt;information-queue&lt;/code&gt; bound with &lt;code&gt;log-level&lt;/code&gt; set to &lt;code&gt;information&lt;/code&gt; using the code above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lSGyYxT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/rabbitmq-management-queue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lSGyYxT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/rabbitmq-management-queue.png" alt="RabbitMQ Management Queue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/#The-result"&gt;&lt;/a&gt;The result
&lt;/h2&gt;

&lt;p&gt;With all of this in place, we can start using this topology.&lt;/p&gt;

&lt;p&gt;Firstly, we have to create a &lt;code&gt;Headers Exchange&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7z-l5aH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/headers-exchange-created-successfully.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7z-l5aH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/headers-exchange-created-successfully.png" alt="Headers Exchange created successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;information&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; queues have to be created and bound the &lt;code&gt;log-level&lt;/code&gt; property to them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q7jdsamk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/queues-created-successfully.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q7jdsamk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/queues-created-successfully.png" alt="Queues created successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Consumer&lt;/code&gt; from the last article will be used, the one without events, but the one with events can be used as well. There is no need to create another &lt;code&gt;Consumer&lt;/code&gt; because its responsibility is to listen to &lt;code&gt;Queues&lt;/code&gt; that are subscribed to.&lt;/p&gt;

&lt;p&gt;Now the messages can be produced. There will be two messages for the &lt;code&gt;information&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; log levels, and one that is not bound to any header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BfZ6XS4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/producing-consuming-messages.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BfZ6XS4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/28/rabbitmq-headers-exchange-with-docker-in-dotnet/producing-consuming-messages.png" alt="Producing and consuming messages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the picture above can be seen, that the first two messages which had the headers bound correctly were received by the consumer, but the final messages which don't have any headers were not received.&lt;/p&gt;

&lt;p&gt;The entire code for this topology and the RabbitMQ series can be found on my GitHub account: &lt;a href="https://github.com/StefanescuEduard/RabbitMQ_POC"&gt;https://github.com/StefanescuEduard/RabbitMQ_POC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>amqp</category>
      <category>docker</category>
      <category>dotnet</category>
      <category>rabbitmq</category>
    </item>
    <item>
      <title>RabbitMQ Consumer with Docker in .NET</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 09:56:33 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/rabbitmq-consumer-with-docker-in-net-3d9e</link>
      <guid>https://dev.to/eduardstefanescu/rabbitmq-consumer-with-docker-in-net-3d9e</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This is the last article from the RabbitMQ series. In this series, I explained all the RabbitMQ nodes using .NET and Docker. There will be other two articles, the first one is dedicated just for the &lt;code&gt;Headers Exchange&lt;/code&gt;, because this type of &lt;code&gt;Exchange&lt;/code&gt; needs more attention, considering that the sent messages need to be binding to the &lt;code&gt;Exchange&lt;/code&gt; using &lt;code&gt;x-match&lt;/code&gt; property and to the &lt;code&gt;Queue&lt;/code&gt; using defined properties. And in the second one, I will explain a safer way of consuming messages and closing the connection, because this series is more educational oriented and plain methods were used for a better understanding.&lt;/p&gt;

&lt;p&gt;In this article the &lt;code&gt;Consumer&lt;/code&gt; node of the RabbitMQ topology will be presented, in the first part the core concepts will be cover, and in the second part, each line of code will be explained.\&lt;br&gt;
The first article from this series contains the environment setup with Docker and the core fundamentals of RabbitMQ. You can check the other three articles here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/02/29/rabbitmq-producer-with-docker-in-dotnet/&lt;/a&gt; (environment setup)&lt;/li&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/03/07/rabbitmq-exchange-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/03/07/rabbitmq-exchange-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://stefanescueduard.github.io/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/" rel="noopener noreferrer"&gt;https://stefanescueduard.github.io/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Introduction" rel="noopener noreferrer"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;The RabbitMQ &lt;code&gt;Consumer&lt;/code&gt; it's the node to which the &lt;code&gt;Queues&lt;/code&gt; are connected. This will receive all the messages sent by the &lt;code&gt;Producer&lt;/code&gt; and followed some path to be consumed. A real-life example for the &lt;code&gt;Consumer&lt;/code&gt; it will be, a logging system, where the &lt;code&gt;Producer&lt;/code&gt; is the app that sent the log message and the &lt;code&gt;Consumer&lt;/code&gt; is the Console or the API that will process the received message.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Useful-tips" rel="noopener noreferrer"&gt;&lt;/a&gt;Useful tips
&lt;/h3&gt;

&lt;p&gt;Here are some tips that I found useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The lifetime of a &lt;code&gt;Consumer&lt;/code&gt; is as long as the application lifetime;&lt;/li&gt;
&lt;li&gt;  It's not recommended to have a &lt;code&gt;Consumer&lt;/code&gt; that consumes only one message, but it's totally fine to have a &lt;code&gt;Consumer&lt;/code&gt; subscribed to a &lt;code&gt;Queue&lt;/code&gt; as long as it sent multiple messages. That's because, for obvious reasons, it's not necessary to have this entire system send only one message;&lt;/li&gt;
&lt;li&gt;  A &lt;code&gt;Consumer&lt;/code&gt; has a uniquely identifiable tag and a subscription ID, which is the connection link with the &lt;code&gt;Queue&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;  The exclusivity to the &lt;code&gt;Consumer&lt;/code&gt; can be made using the &lt;code&gt;exclusive&lt;/code&gt; flag, which means that the &lt;code&gt;Consumer&lt;/code&gt; will receive messages from only one &lt;code&gt;Queue&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;  And some &lt;code&gt;Consumers&lt;/code&gt; can have a higher priority to the same messages over other &lt;code&gt;Consumers&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the &lt;code&gt;Consumers&lt;/code&gt;'s properties can be read on the RabbitMQ website: &lt;a href="https://www.rabbitmq.com/consumers.html" rel="noopener noreferrer"&gt;https://www.rabbitmq.com/consumers.html&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Creating-the-Consumer" rel="noopener noreferrer"&gt;&lt;/a&gt;Creating the &lt;code&gt;Consumer&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;First of all, we need to know how many queues are listening to this consumer, so a message is prompt to enter the number of queues. After that, a connection to the RabbitMQ Server is made using a URI and specifying the &lt;code&gt;ConnectionTimeout&lt;/code&gt; to its maximum value. This value is used just for this article purposes, also all the &lt;code&gt;ConnectionFactory&lt;/code&gt; properties with few examples can be found here: &lt;a href="https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.2.4/rabbitmq-dotnet-client-3.2.4-client-htmldoc/html/type-RabbitMQ.Client.ConnectionFactory.html" rel="noopener noreferrer"&gt;https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.2.4/rabbitmq-dotnet-client-3.2.4-client-htmldoc/html/type-RabbitMQ.Client.ConnectionFactory.html&lt;/a&gt;.\&lt;br&gt;
You can check the first article where is another approach of creating the &lt;code&gt;ConnectionFactory&lt;/code&gt; using the properties &lt;code&gt;Hostname&lt;/code&gt;, &lt;code&gt;UserName&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static IConnection connection;
private static IModel channel;

public static void Main()
{
    Console.Write("Listening queues to this consumer: ");
    var listeningQueuesCount = int.Parse(Console.ReadLine());

    var factory = new ConnectionFactory
    {
        Uri = new Uri("amqp://guest:guest@localhost"),
        ContinuationTimeout = TimeSpan.MaxValue
    };
    connection = factory.CreateConnection();
    channel = connection.CreateModel();
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may notice that the &lt;code&gt;IConnection&lt;/code&gt; and &lt;code&gt;IModel&lt;/code&gt; fields are static, that's because this is a Console App, and these two fields are used inside of each thread that is listening to a &lt;code&gt;Queue&lt;/code&gt;. But these fields will be closed and disposed before the application finishes its execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Listening-to-the-Queue-s" rel="noopener noreferrer"&gt;&lt;/a&gt;Listening to the &lt;code&gt;Queue(s)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Before start listening to the &lt;code&gt;Queue(s)&lt;/code&gt;, a &lt;code&gt;CancellationTokenSource&lt;/code&gt; is created in order to be passed on each execution thread that will display a message, that's because the thread will have the same lifetime as the application, and it's also a safety check to cancel the &lt;code&gt;Consumer&lt;/code&gt; subscription once the application ends.\&lt;br&gt;
According to the number of &lt;code&gt;Queues&lt;/code&gt; entered, this &lt;code&gt;Consumer&lt;/code&gt; is listening to, the &lt;code&gt;Queue&lt;/code&gt; name is asked in order to create the connection between the &lt;code&gt;Consumer&lt;/code&gt; and the &lt;code&gt;Queue&lt;/code&gt;.\&lt;br&gt;
Then for each &lt;code&gt;Queue&lt;/code&gt;, a thread is created, and start listening to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
var cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;

for (var queueIndex = 0; queueIndex &amp;lt; listeningQueuesCount; queueIndex++)
{
    Console.Write($"Queue[{queueIndex}] name: ");
    var queueName = Console.ReadLine();

    var thread = new Thread(() =&amp;gt; DisplayQueueMessage(queueName, cancellationToken));
    thread.Start();
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Displaying-the-received-message" rel="noopener noreferrer"&gt;&lt;/a&gt;Displaying the received message
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;DisplayQueueMessage&lt;/code&gt; has the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;queueName&lt;/code&gt; which will listen to;&lt;/li&gt;
&lt;li&gt;  And the &lt;code&gt;cancellationToken&lt;/code&gt; which represents the listener thread lifetime;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void DisplayQueueMessage(string queueName, CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        BasicGetResult result = channel.BasicGet(queueName, false);
        if (result != null)
        {
            Console.WriteLine($"Message: {Encoding.UTF8.GetString(result.Body)}");
            channel.BasicAck(result.DeliveryTag, false);
            Console.WriteLine("Press any key to stop consuming messages.");
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#DisplayQueueMessage-method-explanation" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;code&gt;DisplayQueueMessage&lt;/code&gt; method explanation
&lt;/h4&gt;

&lt;p&gt;As is described earlier, the listener will exist until the &lt;code&gt;cancellationToken&lt;/code&gt; is not requested.\&lt;br&gt;
On line 5 the message is retrieved from the &lt;code&gt;Queue&lt;/code&gt; and is checked if it's &lt;code&gt;null&lt;/code&gt;. If it's not &lt;code&gt;null&lt;/code&gt;, the message body which is an array of bytes will be decoded using the same encoding format as it was used to encode the message.\&lt;br&gt;
After displaying the retrieved message, the result is acknowledged in order to be deleted from the &lt;code&gt;Queue&lt;/code&gt; and to display the next message.\&lt;br&gt;
This is not the nicest way to listen to the messages and can cause performance issues, that's why I will create another article about listening events, that will be raised only when a message is published and redirected to a specific &lt;code&gt;Queue&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Ending-the-connection" rel="noopener noreferrer"&gt;&lt;/a&gt;Ending the connection
&lt;/h3&gt;

&lt;p&gt;After the thread was created for each &lt;code&gt;Queue&lt;/code&gt;, a message is prompt in order to display how many &lt;code&gt;Queues&lt;/code&gt; are listening to the &lt;code&gt;Consumer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    Console.WriteLine(
        $"Consumer created successfully and listening to {listeningQueuesCount} queue(s).");
    Console.ReadKey();

    cancellationTokenSource.Cancel();

    WaitHandle.WaitAny(new[] { cancellationToken.WaitHandle });

    channel.Close();
    channel.Dispose();
    connection.Close();
    connection.Dispose();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;code&gt;cancellationTokenSource&lt;/code&gt; is canceled, in order to stop the listening threads, after that the connection and channel are closed and disposed.&lt;br&gt;
The &lt;code&gt;WaitHandle&lt;/code&gt; is used to end the connection and the channel safely after the cancellation is signaled.&lt;/p&gt;

&lt;p&gt;You can find the solution, with all four nodes on my Github account: &lt;a href="https://github.com/StefanescuEduard/RabbitMQ_POC" rel="noopener noreferrer"&gt;https://github.com/StefanescuEduard/RabbitMQ_POC&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/21/rabbitmq-consumer-with-docker-in-dotnet/#Topology-result" rel="noopener noreferrer"&gt;&lt;/a&gt;Topology result
&lt;/h3&gt;

&lt;p&gt;By following the &lt;a href="http://tryrabbitmq.com/" rel="noopener noreferrer"&gt;http://tryrabbitmq.com/&lt;/a&gt; topology described in the previous articles, firstly the &lt;code&gt;Exchange&lt;/code&gt; is created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fexchange-creation.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%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fexchange-creation.png" alt="Exchange creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then two &lt;code&gt;Queues&lt;/code&gt; are created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fqueues-creation.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%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fqueues-creation.png" alt="Queues creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Consumer&lt;/code&gt; is connected to them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fconsumer-creation.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%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fconsumer-creation.png" alt="Consumer creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last step is to publish the messages and checking the &lt;code&gt;Consumer&lt;/code&gt; that is displaying them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Producing messages for both &lt;code&gt;routing-keys&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fproducer-creation.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%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fproducer-creation.png" alt="Producer creation"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Checking &lt;code&gt;Consumer&lt;/code&gt; to see the sent messages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fconsumer-listening.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%2Feduardstefanescu.dev%2F2020%2F03%2F21%2Frabbitmq-consumer-with-docker-in-dotnet%2Fconsumer-listening.png" alt="Consumer listening"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>amqp</category>
      <category>docker</category>
      <category>rabbitmq</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>RabbitMQ Queue with Docker in .NET</title>
      <dc:creator>Eduard Stefanescu</dc:creator>
      <pubDate>Sun, 07 Mar 2021 09:52:47 +0000</pubDate>
      <link>https://dev.to/eduardstefanescu/rabbitmq-queue-with-docker-in-net-307d</link>
      <guid>https://dev.to/eduardstefanescu/rabbitmq-queue-with-docker-in-net-307d</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/"&gt;https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This is the third article from a series of four about RabbitMQ &lt;code&gt;Queue&lt;/code&gt;. The first part contains a brief introduction into the &lt;code&gt;Queue&lt;/code&gt; concepts and in the second part, each line of the code is explained. You can check the first article where the RabbitMQ core concepts are presented and also the environment setup with Docker and the &lt;code&gt;Producer&lt;/code&gt; are explained step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#Introduction"&gt;&lt;/a&gt;Introduction
&lt;/h2&gt;

&lt;p&gt;The RabbitMQ &lt;code&gt;Queue&lt;/code&gt; is positioned in the &lt;code&gt;Message Broker&lt;/code&gt; section with the &lt;code&gt;Exchange&lt;/code&gt;, and can be seen as buffer storage, that receives messages through a stream based on the &lt;code&gt;binding key&lt;/code&gt; from the &lt;code&gt;Exchange&lt;/code&gt; which also receives the messages from one or many &lt;code&gt;Producers&lt;/code&gt;. They are acting like a Queue Data Structure, that can be &lt;code&gt;enqueued&lt;/code&gt; and &lt;code&gt;dequeued&lt;/code&gt;, using the FIFO rule.\&lt;br&gt;
Some tips about the &lt;code&gt;Queues&lt;/code&gt;, that I find useful are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A &lt;code&gt;Queue&lt;/code&gt; name can't start the &lt;code&gt;amq&lt;/code&gt; name, because is restricted by the &lt;code&gt;Broker&lt;/code&gt; for internal usages.&lt;/li&gt;
&lt;li&gt;  If the &lt;code&gt;Queue&lt;/code&gt; name is not specified a random one will be assigned to it.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Queues&lt;/code&gt; with the same name can be created on the same channel, by only the last one will be kept.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the RabbitMQ &lt;code&gt;Queue&lt;/code&gt; properties can be on their site: &lt;a href="https://www.rabbitmq.com/queues.html"&gt;https://www.rabbitmq.com/queues.html&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#Creating-the-Queue"&gt;&lt;/a&gt;Creating the &lt;code&gt;Queue&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To start creating a &lt;code&gt;Queue&lt;/code&gt; firstly the connection to the RabbitMQ server should be built using the &lt;code&gt;ConnectionFactory&lt;/code&gt;; is the same setup as in the previous article about RabbitMQ &lt;code&gt;Exchange&lt;/code&gt; using a &lt;code&gt;URI&lt;/code&gt;. But in the first article where the &lt;code&gt;Producer&lt;/code&gt; is created, the connection was created using explicit properties of &lt;code&gt;ConnectionFactory&lt;/code&gt; (i.e. &lt;code&gt;Hostname&lt;/code&gt;, &lt;code&gt;UserName&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#Connection-setup"&gt;&lt;/a&gt;Connection setup
&lt;/h3&gt;

&lt;p&gt;As you can see in the below chunk code, all these properties are embedded into one &lt;code&gt;Uri&lt;/code&gt; instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var factory = new ConnectionFactory
{
    Uri = new Uri("amqp://guest:guest@localhost"),
    ContinuationTimeout = TimeSpan.MaxValue
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ConnectionTimeout&lt;/code&gt; property was set to its maximum value because I didn't want the connection to expire, but this is just for this article purposes. If you are interested to find all the &lt;code&gt;ConnectionFactory&lt;/code&gt; properties, they are well documented here with one example: &lt;a href="https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.2.4/rabbitmq-dotnet-client-3.2.4-client-htmldoc/html/type-RabbitMQ.Client.ConnectionFactory.html"&gt;https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.2.4/rabbitmq-dotnet-client-3.2.4-client-htmldoc/html/type-RabbitMQ.Client.ConnectionFactory.html&lt;/a&gt;. This is the documentation for version 3.2.4 when you read this article the RabbitMQ Client for .NET may be updated, so it's possible that some properties may be changed, deprecated or removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#Developer-input"&gt;&lt;/a&gt;Developer input
&lt;/h3&gt;

&lt;p&gt;You may wonder why the user or the developer input is involved in this, is because this series of articles about &lt;code&gt;RabbitMQ&lt;/code&gt; is more educational rather than a solution-oriented approach. So I wanted to replicate one to one the &lt;a href="http://tryrabbitmq.com/"&gt;http://tryrabbitmq.com/&lt;/a&gt; concept of learning the basic principles of RabbitMQ using .NET.\&lt;br&gt;
Thus, after the connection to the RabbitMQ Server was built, the user is asked to enter the number of &lt;code&gt;Queues&lt;/code&gt; that he wants to create and to provide for each &lt;code&gt;Queue&lt;/code&gt; a name and the &lt;code&gt;routing key&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for (var queueIndex = 0; queueIndex &amp;lt; queuesCount; queueIndex++)
{
    Console.Write($"Queue[{queueIndex}] name: ");
    var queueName = Console.ReadLine();

    Console.Write($"Routing key for Queue[{queueIndex}]: ");
    var routingKey = Console.ReadLine();
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#Connection-establishment"&gt;&lt;/a&gt;Connection establishment
&lt;/h3&gt;

&lt;p&gt;When the required properties are entered, for each &lt;code&gt;Queue&lt;/code&gt; a &lt;code&gt;Connection&lt;/code&gt; and a communication &lt;code&gt;Channel&lt;/code&gt; will be created. After that, the &lt;code&gt;Queue&lt;/code&gt; is declared, and the bound to the &lt;code&gt;Exchange&lt;/code&gt; that has the same name for the entire solution (i.e. test-exchange). If the creation and the binding were ended successfully, then a message is prompted informing the user that the &lt;code&gt;Queue&lt;/code&gt; was created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    using (IConnection connection = factory.CreateConnection())
    {
        using (channel = connection.CreateModel())
        {
            channel.QueueDeclare(queue: queueName,
                durable: false,
                exclusive: false,
                autoDelete: false,
                arguments: null);

            channel.QueueBind(queue: queueName,
                exchange: "test-exchange",
                routingKey: routingKey);
        }
    }

    Console.WriteLine(value: $"Queue {queueName} created.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#QueueDeclare-parameters"&gt;&lt;/a&gt;&lt;code&gt;QueueDeclare&lt;/code&gt; parameters
&lt;/h4&gt;

&lt;p&gt;Let's dig a little bit deep into the parameters of the &lt;code&gt;QueueDeclare&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;queue&lt;/code&gt; it's self-evident that it refers to the &lt;code&gt;Queue&lt;/code&gt; name;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;durable&lt;/code&gt; represents the lifetime of the &lt;code&gt;Queue&lt;/code&gt; in the &lt;code&gt;Broker&lt;/code&gt;, if it's set to false the &lt;code&gt;Queue&lt;/code&gt; will end when the &lt;code&gt;Broker&lt;/code&gt; does too;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;autoDelete&lt;/code&gt; is used to specify the lifetime of the &lt;code&gt;Queue&lt;/code&gt; based on its subscriptions. The &lt;code&gt;Queue&lt;/code&gt; will be deleted if the last &lt;code&gt;Consumer&lt;/code&gt; subscribed to it, unsubscribes;&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;arguments&lt;/code&gt; are used to sent information about the &lt;code&gt;Queue&lt;/code&gt; (e.g. length limit) to the &lt;code&gt;Broker&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;QueueBind&lt;/code&gt;'s parameters are self-explanatory, the first one refers to the &lt;code&gt;queueName&lt;/code&gt;, the second to the &lt;code&gt;exchangeName&lt;/code&gt; and the last one to the &lt;code&gt;routingKey&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/#The-result"&gt;&lt;/a&gt;The result
&lt;/h4&gt;

&lt;p&gt;After the &lt;code&gt;Queues&lt;/code&gt; are created, a message is prompted to the user with how many &lt;code&gt;Queues&lt;/code&gt; were created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--khKkDTwy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/rabbitmq-queue-created-console.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--khKkDTwy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/rabbitmq-queue-created-console.png" alt="RabbitMQ Queue Created Console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The created &lt;code&gt;Queues&lt;/code&gt; can also be seen on the RabbitMQ Management page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DlGAbY1c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/rabbitmq-queue-created-management.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DlGAbY1c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://eduardstefanescu.dev/2020/03/14/rabbitmq-queue-with-docker-in-dotnet/rabbitmq-queue-created-management.png" alt="RabbitMQ Queue Created Management"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, all we have to do is to create the &lt;code&gt;Consumer&lt;/code&gt;, and the entire topology will be ready to be used. The &lt;code&gt;Consumer&lt;/code&gt; will be created in the next article, this being the last one from this series.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article, if you find it interesting please share it with your colleagues and friends. Or if you find something that can be improved please let me know.&lt;/p&gt;

</description>
      <category>amqp</category>
      <category>docker</category>
      <category>rabbitmq</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
