<?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: Sergiy Korzh</title>
    <description>The latest articles on DEV Community by Sergiy Korzh (@korzh).</description>
    <link>https://dev.to/korzh</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%2F201835%2F176b55bc-33e6-4f5e-80b4-e263971caf0c.jpeg</url>
      <title>DEV Community: Sergiy Korzh</title>
      <link>https://dev.to/korzh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/korzh"/>
    <language>en</language>
    <item>
      <title>How to add CRUD functionality in ASP.NET Core app in 10 minutes</title>
      <dc:creator>Sergiy Korzh</dc:creator>
      <pubDate>Tue, 01 Jun 2021 06:15:36 +0000</pubDate>
      <link>https://dev.to/korzh/how-to-add-crud-functionality-in-asp-net-core-app-in-10-minutes-4cde</link>
      <guid>https://dev.to/korzh/how-to-add-crud-functionality-in-asp-net-core-app-in-10-minutes-4cde</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;One of the first tasks for most business applications is to implement CRUD (Create, Read, Update, Delete) operations for the main entities the app works with. &lt;/p&gt;

&lt;p&gt;Every developer faces the following problems as part of solving the task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The creation of CRUD pages and forms is very boring and time-consuming. Believe me, I’ve been there a lot of times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you do it manually, it can be very slow and error-prone (missed fields, forgotten validators, etc).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Of course, you can use the scaffolding tool provided by Visual Studio. &lt;br&gt;
However, it’s also not a quick process either, because you need to run that tool for each model class. &lt;br&gt;
As a result, you get many .cs and .cshtml files, which you'll have to edit manually if something in the default behavior or appearance doesn't suit your needs. &lt;br&gt;
In the event of changes in the model classes, you'll need to update those generated controllers and pages manually &lt;br&gt;
or regenerate the code and forms from scratch for each affected model class.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moreover, even the built-in scaffolding doesn't provide some important, often essential functions such as paging or search.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution: EasyData library
&lt;/h2&gt;

&lt;p&gt;To solve most (if not all) of those problems we created the &lt;a href="https://github.com/KorzhCom/EasyData"&gt;EasyData library&lt;/a&gt;. &lt;br&gt;
The main advantage of EasyData is that it employs a declarative approach. &lt;/p&gt;

&lt;p&gt;The whole process can be split into two main steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You “describe” what data (entities and attributes) you want to work with and &lt;br&gt;
how your application should work with that data (types, constraints, relations between entities, etc). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Based on this information, the EasyData library establishes an API endpoint for CRUD operations and a vanilla JavaScript-based UI &lt;br&gt;
that lets your users perform those operations via the API.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most wonderful thing here is that when using Entity Framework Core, &lt;br&gt;
all you need for the first step (“describing” the data) is your DbContext. &lt;br&gt;
Simply “feed” it to the library, and EasyData automatically extracts all the information needed to create the API endpoints and CRUD UI.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick demo
&lt;/h2&gt;

&lt;p&gt;Here's a small introduction video that shows how EasyData works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4SJt4seg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn.korzh.com/img/easydata-demo01.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4SJt4seg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn.korzh.com/img/easydata-demo01.gif" alt="EasyData quick demo" title="EasyData quick demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First of all, to test EasyData you can open and run one of the &lt;a href="https://github.com/korzh/EasyData/tree/master/samples"&gt;sample projects&lt;/a&gt; available in this repository. &lt;/p&gt;

&lt;p&gt;Installing EasyData to your project takes the following three simple steps:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Install EasyData NuGet packages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EasyData.AspNetCore&lt;/li&gt;
&lt;li&gt;EasyData.EntityFrameworkCore.Relational&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Add EasyData middleware in &lt;code&gt;Startup.Configure&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EasyData.Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;    &lt;span class="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;UseEndpoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoints&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;endpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapEasyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&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;endpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapRazorPages&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 middleware options, we also specify the type of DbContext object that will be used as the source of the metadata.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Set up a catch-all page for all CRUD operations
&lt;/h3&gt;

&lt;p&gt;If you're using Razor Pages, add a new page (for example &lt;code&gt;EasyData.chstml&lt;/code&gt;). If it’s MVC, you'll need a controller and a view.&lt;br&gt;
This page will "catch" all URLs that begin with a certain prefix (&lt;code&gt;/easydata&lt;/code&gt; by default but it's configurable). So, we use a special catch-all parameter in the route definition (&lt;code&gt;"/easydata/{**entity}"&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We also add EasyData styles and the script file (&lt;code&gt;easydata.min.js&lt;/code&gt;), which renders the data-management UI and handles all CRUD operations on the client-side.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@page "/easydata/{**entity}"
@{
    ViewData["Title"] = "EasyData";
}
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.korzh.com/ed/1.2.2/easydata.min.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"EasyDataContainer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

@section Scripts {
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.korzh.com/ed/1.2.2/easydata.min.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&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="nx"&gt;easydata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EasyDataViewDispatcher&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Now you can run your web app, open the &lt;code&gt;/easydata&lt;/code&gt; URL and enjoy CRUD functionality.&lt;/p&gt;

&lt;p&gt;The result will be something like this:&lt;/p&gt;

&lt;h4&gt;
  
  
  List view screen for one entity:
&lt;/h4&gt;

&lt;p&gt;
    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yL-rn2lx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot01.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yL-rn2lx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot01.jpg" alt="List view screen for Orders entity"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  "Edit Record" dialog:
&lt;/h4&gt;

&lt;p&gt;
    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AmXGXx2C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot02.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AmXGXx2C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot02.jpg" alt="Edit Record dialog"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  "Lookup" dialog (was opened from "Edit Record"):
&lt;/h4&gt;

&lt;p&gt;
    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--00y3IfPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot03.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--00y3IfPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.korzh.com/img/blog/edintro/easydata-sshot03.jpg" alt="Lookup dialog"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Let's briefly go over how all this magic works. &lt;br&gt;
As we mentioned before EasyData takes care of three main things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It collects database metadata.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It establishes an API for the main CRUD operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It renders UI (again, based on the metadata) and processes all user interactions in that UI.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s explore all these parts in detail.&lt;/p&gt;
&lt;h3&gt;
  
  
  Metadata
&lt;/h3&gt;

&lt;p&gt;Metadata is the data about your data: what entities (tables) are stored in your database, &lt;br&gt;
how they're connected, what attributes (fields) they have, what  the types of attributes are &lt;br&gt;
and what the constraints are with respect to the values we can store in those attributes.&lt;/p&gt;

&lt;p&gt;EasyData collects metadata (in one way or another) and stores it in the instance of &lt;code&gt;MetaData&lt;/code&gt; class. &lt;br&gt;
This object contains the list of entities (tables), the attributes (fields) for each entity, the connections between entities, &lt;br&gt;
and some additional information used in API and during UI rendering and processing.&lt;/p&gt;

&lt;p&gt;To fill the MetaData object, we specify a metadata loader. In the example above, we did it with the UseDbContext call. &lt;br&gt;
So, the metadata is loaded from a DbConext object. Currently (in version 1.2) this is the only metadata loader available. &lt;br&gt;
In future versions, it will be possible to load metadata directly from a DbConnection object or perhaps with some other method.&lt;/p&gt;
&lt;h3&gt;
  
  
  EasyData middleware
&lt;/h3&gt;

&lt;p&gt;EasyData middleware is responsible for establishing a REST API for all CRUD (and not only) operations initiated by the client side.&lt;/p&gt;

&lt;p&gt;To add the middleware to your pipeline use &lt;code&gt;MapEasyData&lt;/code&gt; extension function inside &lt;code&gt;UseEndpoints&lt;/code&gt; configuration delegate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseEndpoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoints&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;endpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapEasyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&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;This call should be made before &lt;code&gt;MapMvc&lt;/code&gt; or &lt;code&gt;MapRazorPages&lt;/code&gt;. &lt;br&gt;
By default, EasyData middleware is assigned to &lt;code&gt;/api/easydata endpoint&lt;/code&gt;, but you can change it via the configuration function (action) passed in the parameter.&lt;/p&gt;

&lt;p&gt;The only thing that's required in order to configure for &lt;code&gt;MapEasyData&lt;/code&gt; is to tell it where to take the metadata. &lt;br&gt;
Currently, there's just one option available: getting metadata from a DbContext. &lt;br&gt;
So, that’s why we add &lt;code&gt;UseDbContext&amp;lt;AppDbContext&amp;gt;()&lt;/code&gt; call in the example above. &lt;br&gt;
Besides getting metadata, &lt;code&gt;UseDbContext&lt;/code&gt; also provides our middleware with all the means for performing CRUD operations (via the DbContext object).&lt;/p&gt;

&lt;h3&gt;
  
  
  EasyData UI root page
&lt;/h3&gt;

&lt;p&gt;The third part of the EasyData setup process is the page where the CRUD user interface is rendered. &lt;br&gt;
It must be a so-called "catch-all" Razor page or MVC view. &lt;br&gt;
By default, this page must be opened for any path that starts with the &lt;code&gt;/easydata/&lt;/code&gt; prefix.&lt;br&gt;
(So, all paths like &lt;code&gt;/easydata/student&lt;/code&gt; or &lt;code&gt;/easydata/invoice&lt;/code&gt; must be processed by this page.)&lt;/p&gt;

&lt;p&gt;NB: &lt;code&gt;/easydata&lt;/code&gt; is the default prefix. &lt;br&gt;
You can use another name, but in this case, it will be necessary to specify it in the options of our &lt;code&gt;RootDispatcherView&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Our catch-all page can contain any HTML element of your choice. &lt;br&gt;
However, to ensure the visualization and normal operation of the CRUD UI, it must include the following 4 elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element with a reference to EasyData CSS file (&lt;code&gt;easydata.min.cs&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Container (empty &lt;code&gt;div&lt;/code&gt; element), in which our interface will be displayed. &lt;br&gt;
By default, it must have the ID &lt;code&gt;EasyDataContainer&lt;/code&gt;, but this can also be configured with options.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element with a reference to &lt;code&gt;easydata.min.js&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And a small script that creates and launches the &lt;code&gt;EasyDataViewDispatcher&lt;/code&gt; object on page load.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of the simplest “catch-all” page you can see in the Getting Started section above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Currently, EasyData can work with .NET Core 3.1 and .NET 5. &lt;br&gt;
Obviously, all ASP.NET Core and Entity Framework Core versions that can work with the specified releases of .NET (Core) are supported. &lt;br&gt;
However, it won't be a problem to add support for previous versions of .NET Core or even .NET Framework 4.x. &lt;br&gt;
If anyone needs it, please &lt;a href="https://github.com/KorzhCom/EasyData/issues"&gt;submit an issue&lt;/a&gt; in EasyData's GitHub repository.&lt;/p&gt;

&lt;p&gt;EasyData can be a good tool with which to quickly prototype a new project or create a POC (proof of concept) &lt;br&gt;
when we already understand what data we'll need but don't want to spend a lot of time on the simplest operations with that data. &lt;br&gt;
However, we hope that in time it will be possible to fully use this solution in the production environment.&lt;/p&gt;

&lt;p&gt;So, we look forward to hearing from you with any comments or advice you may have. Of course, don't forget to ad a start for the EasyData repository on GitHub, especially if this library helped you and saved some time.&lt;/p&gt;

&lt;p&gt;So, we look forward to hearing from you with any comments or advice you may have. &lt;br&gt;
Of course, don't forget to add a star for the &lt;a href="https://github.com/KorzhCom/EasyData"&gt;EasyData repository on GitHub&lt;/a&gt;, &lt;br&gt;
especially if this library helped you and saved some time. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>aspnetcore</category>
      <category>crud</category>
      <category>entityframework</category>
    </item>
    <item>
      <title>How to add extra user claims in ASP.NET Core web-app</title>
      <dc:creator>Sergiy Korzh</dc:creator>
      <pubDate>Fri, 26 Jul 2019 09:09:03 +0000</pubDate>
      <link>https://dev.to/korzh/how-to-add-extra-user-claims-in-asp-net-core-web-app-770</link>
      <guid>https://dev.to/korzh/how-to-add-extra-user-claims-in-asp-net-core-web-app-770</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core has sufficiently developed tools for implementing authentication and authorization mechanisms in your projects. These tools are available out-of-the-box and rather simple in configuring. Even the starting web-project created with Visual Studio wizard already includes all the necessary parts of the authorization subsystem (Registration/Login/User Profile forms, Reset password procedure, etc.)&lt;/p&gt;

&lt;p&gt;However, some at first glance, simple tasks require a deeper understanding of the internal structure of ASP.NET Core Identity. &lt;/p&gt;

&lt;p&gt;In this article, we will discuss one of these tasks and suggest a solution to it using the &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims" rel="noopener noreferrer"&gt;claims-based approach&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Let's suppose we created a new ASP.NET Core project using one of the default templates and chose "Individual user account" option for "Authentication".&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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim01.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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim01.png" title="ASP.NET Core - new web-app project with an authentication" alt="ASP.NET Identity new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now when we start that newly created project and register new user we will see something like &lt;code&gt;Hello YourEmailAddress@YourCompany.com&lt;/code&gt; in the top right part of the index web-page.&lt;/p&gt;

&lt;p&gt;Obviously, such kind of greeting is useless in a real-world application and you would like to see the name of the currently logged user there instead (e.g. &lt;code&gt;Hello John Doe&lt;/code&gt;).&lt;br&gt;&lt;br&gt;
Let's figure out how to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Here we guess you are already familiar with the claims and &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims" rel="noopener noreferrer"&gt;claims-based approach&lt;/a&gt; for authorization used in ASP.NET Core Identity. If not - please read &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/" rel="noopener noreferrer"&gt;ASP.NET Core Security&lt;/a&gt; article first.&lt;/p&gt;

&lt;p&gt;To achieve our goal we need to do 2 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add necessary information to the list of the claims attached to the user's identity.&lt;/li&gt;
&lt;li&gt;Have a simple way of getting that info when needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But before implementing these two tasks we will need to add a new ContactName field to our model class and update our registration and user management pages accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Preparations
&lt;/h2&gt;

&lt;p&gt;Before we can add a new claim to a user object (the one you can access via &lt;code&gt;HttpContext.User&lt;/code&gt;) we need a place to store that additional info somewhere.&lt;br&gt;
Here I am going to describe how to get this done for a new ASP.NET Core project built by a default template.&lt;/p&gt;

&lt;p&gt;If you work on some real-world project - most probably you already did similar changes before. &lt;br&gt;
In this case, you can skip this "preparations" section and move right to the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. New ApplicationUser class
&lt;/h3&gt;

&lt;p&gt;Add a new  &lt;code&gt;ApplicationUser&lt;/code&gt; class with `ContactName' property: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ApplicationUser : IdentityUser
{
    public string ContactName { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, you can add more properties to store some additional information with the user account.&lt;br&gt;
For example: &lt;code&gt;FirstName&lt;/code&gt;, &lt;code&gt;LastName&lt;/code&gt;, &lt;code&gt;Country&lt;/code&gt;, &lt;code&gt;Address&lt;/code&gt;, etc. All of them can be placed to claims the same way as &lt;code&gt;ContactName&lt;/code&gt; we discuss here.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Replace &lt;code&gt;IdentityUser&lt;/code&gt; with &lt;code&gt;ApplicationUser&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now you need to replace &lt;code&gt;IdentityUser&lt;/code&gt; with &lt;code&gt;ApplicationUser&lt;/code&gt; everywhere in your project.&lt;/p&gt;

&lt;p&gt;The default ASP.NET Core template uses predefined &lt;code&gt;IdentityUser&lt;/code&gt; type everywhere. &lt;br&gt;
Since we what to use &lt;code&gt;ApplicationUser&lt;/code&gt; instead of it - we need to search for all inclusions of &lt;code&gt;IdentityUser&lt;/code&gt; in your project and replace with &lt;code&gt;ApplicationUser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will include your DbContext class, one line in &lt;code&gt;Startup&lt;/code&gt; class (in &lt;code&gt;ConfigureServices&lt;/code&gt; method) and two lines with &lt;code&gt;@inject&lt;/code&gt; directives in &lt;code&gt;_LoginPartial.cshtml&lt;/code&gt; view.&lt;/p&gt;

&lt;p&gt;Here is how your new &lt;code&gt;ApplicationDbContext&lt;/code&gt; class will look like after that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ApplicationDbContext : IdentityDbContext&amp;lt;ApplicationUser, IdentityRole, string&amp;gt;
{
    public ApplicationDbContext(DbContextOptions&amp;lt;ApplicationDbContext&amp;gt; options)
        : base(options)
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Update your database.
&lt;/h3&gt;

&lt;p&gt;Now you need to add a new migration and then update your DB.&lt;br&gt;
Just run the following 2 commands from your project's folder:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet ef migrations add AddUserContactName

dotnet ef database update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  4. Update "User Profile" page
&lt;/h3&gt;

&lt;p&gt;Finally, we will need to add our new field to the "User Profile" page to make it possible for users to modify it.&lt;/p&gt;

&lt;p&gt;The default ASP.NET Core template uses all identity-related pages directly from a special Razor UI library (&lt;code&gt;Microsoft.AspNetCore.Identity.UI&lt;/code&gt;).&lt;br&gt;
The good news is: we can override any of those pages if we want. Here are the steps we need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Right-click on your project in VS and select Add | New Scaffolding item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the "Add Scaffold" dialog select &lt;code&gt;Identity&lt;/code&gt; on the left side tree and then &lt;code&gt;Identity&lt;/code&gt; in the main list and click "Add".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the dialog that appears select only &lt;code&gt;Account\Manage\Index&lt;/code&gt; page and then click on "Add" as well.&lt;br&gt;
When the process is finished you will find a new page 'Index.cshtml' in &lt;code&gt;Areas/Identity/Pages&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After that make the following changes to that &lt;code&gt;Index&lt;/code&gt; page:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the Index.cshtml itself add the following piece of markup right before &lt;code&gt;update-profile-button&lt;/code&gt; button.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="form-group"&amp;gt;
  &amp;lt;label asp-for="Input.ContactName"&amp;gt;&amp;lt;/label&amp;gt;
  &amp;lt;input asp-for="Input.ContactName" class="form-control" /&amp;gt;
  &amp;lt;span asp-validation-for="Input.ContactName" class="text-danger"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, in the code-behind file &lt;code&gt;Index.cshtml.cs&lt;/code&gt; we need to modify the view model:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class InputModel
{
    .   .   .   .   .   .

    public string ContactName { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;then the &lt;code&gt;OnGetAsync&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 async Task&amp;lt;IActionResult&amp;gt; OnGetAsync()
{
    .   .   .   .   .   .

    Input = new InputModel
    {
        Email = email,
        PhoneNumber = phoneNumber,
        ContactName = user.ContactName //add this line
    };

    .   .   .   .   .   .

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

&lt;/div&gt;

&lt;p&gt;and the &lt;code&gt;OnPutAsync&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public async Task&amp;lt;IActionResult&amp;gt; OnPostAsync()
{
    .    .    .    .    .    .    .

    if (Input.ContactName != user.ContactName) {
        user.ContactName = Input.ContactName;
        await _userManager.UpdateAsync(user);
    }

    await _signInManager.RefreshSignInAsync(user);
    StatusMessage = "Your profile has been updated";
    return RedirectToPage();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So, after all the changes described above your User Profile page after that registration will look like this:&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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim02.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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim02.png" title="User Profile form with ContactName field" alt="User Profile form with ContactName field"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, all the preparations are finished we can return back to our main task.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Adding the contact name to the claims
&lt;/h2&gt;

&lt;p&gt;A funny thing: the main task is much easier than all the preparations we made before. :)&lt;br&gt;
Moreover, it became even easier because of some changes in version 2.2 of ASP.NET Core (in comparison with version 2.0 as &lt;a href="https://korzh.com/blogs/net-tricks/aspnet-identity-store-user-data-in-claims" rel="noopener noreferrer"&gt;we described before&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;There are only two simple steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  Create own claims principal factory
&lt;/h3&gt;

&lt;p&gt;We need an implementation &lt;code&gt;IUserClaimsPrincipalFactory&lt;/code&gt; which will add necessary information (&lt;code&gt;ContactName&lt;/code&gt; in our case) to the user claims. &lt;br&gt;
The simplest way to do it - is to derive our new class from the default implementation of &lt;code&gt;IUserClaimsPrincipalFactory&lt;/code&gt; and override one method: &lt;code&gt;GenerateClaimsAsync&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 MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory&amp;lt;ApplicationUser&amp;gt;
{
    public MyUserClaimsPrincipalFactory(
        UserManager&amp;lt;ApplicationUser&amp;gt; userManager,
        IOptions&amp;lt;IdentityOptions&amp;gt; optionsAccessor)
        : base(userManager, optionsAccessor)
    {
    }

    protected override async Task&amp;lt;ClaimsIdentity&amp;gt; GenerateClaimsAsync(ApplicationUser user)
    {
        var identity = await base.GenerateClaimsAsync(user);
        identity.AddClaim(new Claim("ContactName", user.ContactName ?? "[Click to edit profile]"));
        return identity;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Register new class in DI container
&lt;/h3&gt;

&lt;p&gt;Then we need to register our new class in the dependency injection container.&lt;br&gt;
The best way for that - to use &lt;code&gt;AddClaimsPrincipalFactory&lt;/code&gt; extension method: &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.AddDefaultIdentity&amp;lt;ApplicationUser&amp;gt;()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores&amp;lt;ApplicationDbContext&amp;gt;()
        .AddClaimsPrincipalFactory&amp;lt;MyUserClaimsPrincipalFactory&amp;gt;();  //&amp;lt;---- add this line
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  2. Accessing new claim from the views
&lt;/h2&gt;

&lt;p&gt;Now we have a new claim associated with our user's identity. That's fine. But how we can get it and render on our view(s)?&lt;br&gt;
Easy. Any view in your application has access to &lt;code&gt;User&lt;/code&gt; object which is an instance of &lt;code&gt;ClaimsPrincipal&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;This object actually holds the list of all claims associated with the current user and you can call its &lt;code&gt;FindFirst&lt;/code&gt; method to get the necessary claim and then read the &lt;code&gt;Value&lt;/code&gt; property of that claim.&lt;/p&gt;

&lt;p&gt;So, we just need to open &lt;code&gt;_LoginPartical.cshtml&lt;/code&gt; file in &lt;code&gt;Pages/Shared/&lt;/code&gt; (or &lt;code&gt;Views/Shared/&lt;/code&gt;) folder and replace the following line:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage"&amp;gt;Hello @User.Identity.Name!&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;with this one:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage"&amp;gt;Hello @(User.FindFirst("ContactName").Value)!&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you instead of something like &lt;code&gt;Hello john.doe@yourcompany.com&lt;/code&gt; at the top of your web-page you should see something like this:&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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim03.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%2Fkorzh.com%2Fstatic%2Fblogs%2Fnet-tricks%2Fanc22-add-extra-claim03.png" title="ASP.NET Core - showing user's contact name instead of email" alt="ASP.NET Identity contact name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all for now. Enjoy!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The article was originally posted on &lt;a href="https://korzh.com/blogs/net-tricks/add-extra-user-claims-aspnet-core-webapp" rel="noopener noreferrer"&gt;Korzh.com blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aspnetcore</category>
      <category>aspnetidentity</category>
      <category>claims</category>
    </item>
  </channel>
</rss>
