<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>asp net core 3.1 tips &#8211; ASP.NET Hosting Reviews and Guides</title>
	<atom:link href="https://topreviewhostingasp.net/tag/asp-net-core-3-1-tips/feed/" rel="self" type="application/rss+xml" />
	<link>https://topreviewhostingasp.net</link>
	<description>ASP.NET Hosting &#124; Reviews &#124; Tips &#38; Tutorial</description>
	<lastBuildDate>Tue, 17 Nov 2020 07:26:43 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://topreviewhostingasp.net/wp-content/uploads/2017/01/cropped-trhaico-32x32.png</url>
	<title>asp net core 3.1 tips &#8211; ASP.NET Hosting Reviews and Guides</title>
	<link>https://topreviewhostingasp.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How to Customize ASP.NET Core Default UI</title>
		<link>https://topreviewhostingasp.net/how-to-customize-asp-net-core-default-ui/</link>
					<comments>https://topreviewhostingasp.net/how-to-customize-asp-net-core-default-ui/#respond</comments>
		
		<dc:creator><![CDATA[Jacques Hunt]]></dc:creator>
		<pubDate>Tue, 17 Nov 2020 06:07:05 +0000</pubDate>
				<category><![CDATA[Hosting Tips]]></category>
		<category><![CDATA[asp net core 3.1]]></category>
		<category><![CDATA[asp net core 3.1 tips]]></category>
		<category><![CDATA[asp.net core]]></category>
		<category><![CDATA[asp.net core tips]]></category>
		<category><![CDATA[asp.net core tutorial]]></category>
		<category><![CDATA[dotnet core]]></category>
		<guid isPermaLink="false">https://topreviewhostingasp.net/?p=2792</guid>

					<description><![CDATA[ASP.NET Core Identity includes a default UI as a Razor library that enables you to quickly add users to an application, without having to build all the UI yourself. The downside is that if you want to customise any of the pages associated with the default UI, then you end up taking ownership of all [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>ASP.NET Core Identity includes a default UI as a Razor library that enables you to quickly add users to an application, without having to build all the UI yourself. The downside is that if you want to customise any of the pages associated with the default UI, then you end up taking ownership of all the logic too. Even if all you want to do is add a CSS class to an element, you&#8217;re stuck maintaining the underlying page handler logic too.</p>



<p>In this post I show how you can replace the Razor views for the default UI, without taking ownership of the business logic stored in the Razor Page <code>PageModel</code> code-behind files. I show how you can use the ASP.NET Core Identity scaffolder to generate the replacement Razor Pages initially, but customise these to use the <em>existing</em>, default, PageModels.</p>



<h2 class="wp-block-heading">ASP.NET Core Identity</h2>



<p>ASP.NET Core Identity is a series of services that provide functionality for managing and signing in users. You can use the Identity services to (among other things):</p>



<p>ASP.NET Core Identity is a series of services that provide functionality for managing and signing in users. You can use the Identity services to (among other things):</p>



<ul>
<li>Create users, and provide sign-in functionality</li>
<li>Secure passwords using best practice, strong, hashing algorithms</li>
<li><a href="https://docs.microsoft.com/en-gb/aspnet/core/security/authentication/accconfirm?view=aspnetcore-3.1#require-email-confirmation">Generate short-lived tokens for email confirmation</a> or <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication/mfa?view=aspnetcore-3.1">multi-factor authentication</a>,</li>
<li>Enable <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-configuration?view=aspnetcore-3.1#lockout">auto-lockout</a> of users to prevent brute-force attacks.</li>
<li><a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/?view=aspnetcore-3.1">Allow logging in with third-party providers</a> like Google and Facebook.</li>
</ul>



<p>The Identity services provide APIs for achieving all these things, but you still have to arrange them all in the right order. You also have to write the UI that users use to interact with the services. Obviously, that&#8217;s a <em>huge</em> investment, and is working with sensitive data, so you have to be very careful not to introduce any security holes.</p>



<p>Prior to ASP.NET Core 2.1, your best bet for implementing this was to use the UI generated from the Visual Studio templates. Unfortunately, using templates means that your UI is fine initially, but you then have a <em>lot</em> of code to maintain. If a bug is found in the templates, you have to go and update it yourself.</p>



<p>Luckily, ASP.NET Core 2.1 introduced a default UI Razor Class Library that meant you could benefit from the same UI, without having dozens of Razor Pages in your application to maintain. If a bug is found in the UI, the NuGet package can be updated, and you seamlessly get the bug fix, and all is great.</p>



<h2 class="wp-block-heading" id="customising-the-default-ui">Customising the default UI</h2>



<p>Of course, using the default UI means: you have to use the default UI. I think it&#8217;s generally unlikely that users will want to use the default UI in its entirety, unless you&#8217;re building internal apps only, or creating a &#8220;throwaway&#8221; app. For a start, the login and register pages include references to developer documentation that most people will want to remove:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="617" class="wp-image-2806" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-1024x617.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-1024x617.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-300x181.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-768x463.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-1536x926.png 1536w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-2048x1234.png 2048w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-3-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Even though the UI is contained in a Razor Class Library, you can &#8220;overwrite&#8221; individual pages, by placing your own Razor Pages in a &#8220;magic&#8221; location in your project. For example, to override the register page, you can create a Razor Page at <em>Areas/Identity/Pages/Register.cshtml</em>:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="708" class="wp-image-2794" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1-1024x708.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1-1024x708.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1-300x207.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1-768x531.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1-50x35.png 50w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-1.png 1247w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>A valid concern would be &#8220;how do I know which pages I can override?&#8221;. Luckily there&#8217;s a .NET Core tool you can use to scaffold pages from Identity in the correct locations, along with supporting files.</p>



<h2 class="wp-block-heading" id="scaffolding-identity-files-with-the-net-cli">Scaffolding Identity files with the .NET CLI</h2>



<p><a href="https://docs.microsoft.com/aspnet/core/security/authentication/scaffold-identity">The documentation for scaffolding Identity pages is excellent</a>, so I&#8217;ll just run through the basics with the .NET CLI here. You can also use Visual Studio, but be sure to follow steps 1-3 below, otherwise you get weird random errors when running the scaffolder.<br /><br />1. Add all the required packages to your application. If you&#8217;re already using EF Core in your app, then you may already have some of these, but make sure they&#8217;re all there, as missing packages can cause frustrating errors locally</p>



<pre class="wp-block-code"><code>dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>Also make sure that the installed package versions match your project version, for example .NET Core 3.1 projects should use packages starting 3.1.x.</em></p>
</blockquote>



<p>2. Confirm your project builds without errors. If it doesn&#8217;t you&#8217;ll get errors when scaffolding files.</p>



<p>3. Install the code generator tool globally using <code>dotnet tool install -g dotnet-aspnet-codegenerator</code>.</p>



<p>4. Run <code>dotnet aspnet-codegenerator identity -lf</code> from the <em>project</em> folder (not the solution folder), to see the list of files you can scaffold:</p>



<pre class="wp-block-code"><code>&gt;  dotnet aspnet-codegenerator identity -lf
Building project ...
Finding the generator 'identity'...
Running the generator 'identity'...
File List:
Account._StatusMessage
Account.AccessDenied
Account.ConfirmEmail
Account.ConfirmEmailChange
Account.ExternalLogin
Account.ForgotPassword
Account.ForgotPasswordConfirmation
Account.Lockout
... 25 more not shown!</code></pre>



<p>In this case, I&#8217;m going to scaffold the Account.Register page, and remove the external login provider section completely.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>You can create a Razor Pages app using the default UI by running </em><code>dotnet new webapp -au Individual -uld</code></p>
</blockquote>



<p>If you&#8217;re scaffolding into a project that&#8217;s configured to use the default UI, you will already have an EF Core <code>IdentityDbContext</code> in your application. Pass the fully namespaced name of the context in the following command, using the <code>-dc</code> switch, when scaffolding your files:</p>



<pre class="wp-block-code"><code>dotnet aspnet-codegenerator identity -dc TestApp.Data.ApplicationDbContext --files "Account.Register"
</code></pre>



<p>After running this command, you&#8217;ll find a bunch more files in the <em>Areas/Identity</em> folder:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="584" class="wp-image-2807" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-1024x584.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-1024x584.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-300x171.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-768x438.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-1536x877.png 1536w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-2048x1169.png 2048w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-3-50x29.png 50w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The generated pages override the equivalents in the default UI package, so any changes you make to <em>Register.cshtml</em> will be reflected in your app. For example, I can delete the external login provider section entirely:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" class="wp-image-2808" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-1024x617.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-1024x617.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-300x181.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-768x463.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-1536x926.png 1536w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-2048x1234.png 2048w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-3-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading" id="remove-your-liabilities-deleting-the-scaffolded-pagemodel">Remove your liabilities &#8211; deleting the scaffolded PageModel</h2>



<p>I don&#8217;t want that code, so I&#8217;m just going to delete it! As I&#8217;m only going to make changes to the Razor views, I can delete the following files:</p>



<ul>
<li><em>Areas/Identity/Pages/Account/Register.cshtml.cs</em> — this is the <code>PageModel</code> implementation I don&#8217;t want to have to maintain</li>
<li><em>Areas/Identity/Pages/Account/ViewImports.cshtml</em> — No longer necessary, as there&#8217;s nothing in the namespace it specifies now</li>
<li><em>Areas/Identity/Pages/_ValidationScriptsPartial.cshtml</em> — A duplicate of the version included in the default UI. No need to override it</li>
<li><em>Areas/Identity/Pages/IdentityHostingStartup.cs</em> — Doesn&#8217;t actually configure anything, so can be deleted</li>
</ul>



<p>Additionally, you can update <em>Areas/Identity/Pages/ViewImports.cshtml</em> to remove the project-specific namespaces, to leave just the following:</p>



<pre class="wp-block-code"><code>@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers</code></pre>



<p>At this point, your app won&#8217;t compile. The <em>Register.cshtml</em> page will complain that you&#8217;ve specified a now non-existent <code>RegisterModel</code> as the <code>PageModel</code> for the Razor Page:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="152" class="wp-image-2804" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-1024x152.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-1024x152.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-300x44.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-768x114.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-1536x228.png 1536w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-2048x303.png 2048w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-2-50x7.png 50w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The final step is to update the <code>@page</code> directive to point to the <em>original</em> <code>RegisterModel</code> that&#8217;s included with the default Identity UI, referenced in full in the example below:</p>



<pre class="wp-block-code"><code>@page
@model Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal.RegisterModel
@{
    ViewData["Title"] = "Register";
}</code></pre>



<p>This is the magic step. Your application will now compile, use your custom Razor views, but use the <em>original</em> Razor Pages <code>PageModel</code>s that are part of the default UI! That&#8217;s much less code to maintain, and less chance to screw something up in your Identity pages</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="561" class="wp-image-2805" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-1024x561.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-1024x561.png 1024w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-300x164.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-768x421.png 768w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-1536x842.png 1536w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2-50x27.png 50w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-2.png 1597w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading" id="what-are-the-downsides-">What are the downsides?</h2>



<p>So what are the downsides of this approach? The only one I can really think of is that you&#8217;re very tightly tied to the <code>PageModel</code>s in the original Identity UI, so you have to be sure that any updates that are made to the Identity UI are reflected in your Razor Page templates as appropriate. The big advantage is that if the default UI package is updated and it doesn&#8217;t make any breaking changes to the Razor templates, then you get the updates with no friction at all.</p>



<p>Another danger is that the inability to customise the <code>PageModel</code> <em>may</em> encourage you to do slightly janky things like <code>@inject</code>-ing services into the Razor views that shouldn&#8217;t be there, and adding additional logic into the Razor views. I&#8217;m not suggesting you should do this. If you _do_ need to change the behaviour of the page handlers, then you should just go ahead and take ownership of that code. The point is that this technique is useful when you <em>don&#8217;t</em> need to change the page handler logic.</p>



<h2 class="wp-block-heading" id="summary">Summary</h2>



<p>In this post I gave some background on ASP.NET Core Identity and the default UI Razor Class Library that provides over 30 Razor Pages &#8220;for free&#8221;. I then showed how you could use the scaffolder tool to override one of these pages when you want to change the Razor template.</p>



<p>The downside of this default approach is that you now have to maintain the page handlers for the scaffolded pages. That&#8217;s 100s of lines of code per page that you must keep up to date when a new package version is released.</p>



<p>I showed how you can avoid that burden by deleting the scaffolded <code>PageModel</code> file, and point your Razor template to the <em>original</em> <code>PageModel</code> that comes as part of the default UI. This lets you update your Razor templates without having to take ownership of the page handler logic, potentially giving you the best of both worlds.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://topreviewhostingasp.net/how-to-customize-asp-net-core-default-ui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Implement Mediator Pattern in ASP.NET Core 3.1</title>
		<link>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/</link>
					<comments>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/#respond</comments>
		
		<dc:creator><![CDATA[Jacques Hunt]]></dc:creator>
		<pubDate>Thu, 05 Nov 2020 04:40:13 +0000</pubDate>
				<category><![CDATA[Hosting Tips]]></category>
		<category><![CDATA[asp net core 3.1]]></category>
		<category><![CDATA[asp net core 3.1 hosting]]></category>
		<category><![CDATA[asp net core 3.1 tips]]></category>
		<category><![CDATA[asp net core 3.1 tutorial]]></category>
		<category><![CDATA[Mediator Pattern asp net core]]></category>
		<guid isPermaLink="false">https://topreviewhostingasp.net/?p=2775</guid>

					<description><![CDATA[For the last few years, Command Query Responsibility Segregation (CQRS) and Event Sourcing (ES) emerged as patterns that can help implement large scale systems, with some risky complexity, by having different models to read or mutate data while also using events as a single source of truth. The mediator pattern is meant to split responsibilities between a caller and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>For the last few years, <strong>Command Query Responsibility Segregation (CQRS) </strong>and <strong>Event Sourcing (ES)</strong> emerged as patterns that can help implement large scale systems, with some risky complexity, by having different models to read or mutate data while also using events as a single source of truth.</p>



<p>The mediator pattern is meant to split responsibilities between a caller and the callee. So instead of having an instance of a class and calling a method directly on it, you ask the mediator to do this for you. While this might sound a lot like doing dependency injection, it actually goes a step further. You don’t even know the interface of the callee. This makes it even more decoupled than you’d have with dependency injection.</p>



<p>The result is that the objects are loosely coupled. They only know about the mediator object, not about each other. Besides the mediator object they’ll likely also have some kind of data transfer object to send parameters for the callee.</p>



<p>For a comparison in the real world, imagine only being able to communicatie with someone or a department through their secretary. You give them a message (the data transfer object) and they pass it on to who you want to reach. Once there’s an answer, the secretary will give it back to you. This way you have no knowledge of who actually answered it.</p>



<h2 class="wp-block-heading" id="advantages-and-disadvantages-of-the-mediator-pattern">Advantages and Disadvantages of the Mediator Pattern</h2>



<p>The mediator pattern brings a couple of advantages:</p>



<ul>
<li>Less coupling: Since the classes don’t have dependencies on each other, they are less coupled.</li>
<li>Easier reuse: Fewer dependencies also helps to reuse classes.</li>
<li>Single Responsibility Principle: The services don’t have any logic to call other services, therefore they only do one thing.</li>
<li>Open/closed principle: Adding new mediators can be done without changing the existing code.</li>
</ul>



<p>There is also one big disadvantage of the mediator pattern:</p>



<ul>
<li>The mediator can become such a crucial factor in your application that it is called a “god class”</li>
</ul>



<h2 class="wp-block-heading">How to Implement Mediator Pattern ASP.NET Core 3.1</h2>



<p>Start by opening Visual Studio and creating an <strong>ASP.NET Core 3.1 Web Application</strong> with a name and at any location.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="444" class="wp-image-2776" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-300x190.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-50x32.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Choose an empty project since this is just a demo.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="466" class="wp-image-2777" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-300x200.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-50x33.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Install the Nuget <code>Swashbuckle.AspNetCore</code> so we can use Swagger to test the API:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="170" class="wp-image-2778" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-300x73.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-50x12.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Open the file <code>Startup.cs</code> and configure both MVC and Swagger, making it easier to test our web API.</p>



<pre class="wp-block-code"><code>    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddSwaggerGen();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();

            app.UseSwagger();

            app.UseSwaggerUI(c =&gt;
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mediator ExampleApi V1");
            });

            app.UseRouting();

            app.UseEndpoints(endpoints =&gt;
            {
                endpoints.MapControllers();
            });
        }
    }.</code></pre>



<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://www.asphostportal.com"><img loading="lazy" decoding="async" width="300" height="271" class="wp-image-2584 aligncenter" src="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01-50x45.png 50w" sizes="(max-width: 300px) 100vw, 300px" /></a></figure>
</div>



<h1 class="wp-block-heading" id="5622">The web API</h1>



<p id="f5e2">Since the objective of this article is to show the mediator pattern, a simple endpoint to manage products should be enough:</p>



<ul>
<li>GET /products — search for products using some filters;</li>
<li>GET /products/{id} — get a product by its unique identifier;</li>
<li>POST /products — create a product;</li>
<li>PUT /products/{id} — update a product by its unique identifier;</li>
<li>DELETE /products/{id} — delete a product by its unique identifier;</li>
</ul>



<p id="5ac4">Create a <code>Controllers</code> folder with another <code>Products</code> folder inside, a <code>ProductsController</code> and the following models:</p>



<pre class="wp-block-code"><code>    [Route("products")]
    public class ProductsController : ControllerBase
    {
        [HttpGet]
        public async Task&lt;IEnumerable&lt;ProductModel&gt;&gt; SearchAsync([FromQuery] string filterQ, [FromQuery] int? skip, [FromQuery] int? take, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpGet("{id:guid}")]
        public async Task&lt;ProductModel&gt; GetByIdAsync([FromRoute] Guid id, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpPost]
        public async Task&lt;CreateProductResultModel&gt; CreateAsync([FromBody] CreateProductModel model, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpPut("{id:guid}")]
        public async Task UpdateAsync([FromRoute] Guid id, [FromBody] UpdateProductModel model, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpDelete("{id:guid}")]
        public async Task DeleteAsync([FromRoute] Guid id, CancellationToken ct)
        {
            throw new NotImplementedException();
        }
    }

    public class CreateProductModel
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreateProductResultModel
    {
        public Guid Id { get; set; }
    }

    public class ProductModel
    {
        public Guid Id { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class UpdateProductModel
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="340" height="295" class="wp-image-2779" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4.png 340w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-300x260.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-50x43.png 50w" sizes="(max-width: 340px) 100vw, 340px" /></figure>



<p>Open the Swagger endpoint (ex: https://localhost:44380/swagger/index.html) and you should see your products endpoint with all the actions:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="615" height="461" class="wp-image-2780" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5.png 615w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-300x225.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-50x37.png 50w" sizes="(max-width: 615px) 100vw, 615px" /></figure>



<h2 class="wp-block-heading" id="7b0a">The database model</h2>



<p id="286a">For demo purposes we are going to use <strong>Entity Framework Core</strong> with data stored in-memory.</p>



<p id="dcdb">Install the Nuget <code>Microsoft.EntityFrameworkCore.InMemory</code>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="141" class="wp-image-2781" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-300x60.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-50x10.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Create a <code>Database</code> folder, the following database context and a product entity:</p>



<pre class="wp-block-code"><code>    public class ApiDbContext : DbContext
    {
        public ApiDbContext(DbContextOptions&lt;ApiDbContext&gt; options) : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity&lt;ProductEntity&gt;(cfg =&gt;
            {
                cfg.HasKey(e =&gt; e.Id);
                cfg.HasAlternateKey(e =&gt; e.ExternalId);

                cfg.HasIndex(e =&gt; e.Code).IsUnique();

                cfg.Property(e =&gt; e.ExternalId)
                    .IsRequired();
                cfg.Property(e =&gt; e.Code)
                    .IsRequired()
                    .HasMaxLength(8);
                cfg.Property(e =&gt; e.Name)
                    .IsRequired()
                    .HasMaxLength(128);
                cfg.Property(e =&gt; e.Price)
                    .IsRequired();
            });
        }
    }

    public class ProductEntity
    {
        public long Id { get; set; }

        public Guid ExternalId { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }</code></pre>



<p>Open the <code>Startup.cs</code> file and add the context into the container as an in-memory database:</p>



<pre class="wp-block-code"><code>services.AddDbContext&lt;ApiDbContext&gt;(o =&gt;
{
    o.UseInMemoryDatabase("ApiDbContext");
});</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="339" height="342" class="wp-image-2782" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7.png 339w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-297x300.png 297w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-150x150.png 150w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-50x50.png 50w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-70x70.png 70w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-127x127.png 127w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-125x125.png 125w" sizes="(max-width: 339px) 100vw, 339px" /></figure>



<h1 class="wp-block-heading" id="eca5">The mediator</h1>



<p id="0adb">Now that we have created the demo endpoint, models and database, its time to configure the mediator.</p>



<p id="bce7">Install the Nuget <code>SimpleSoft.Mediator.Microsoft.Extensions</code> which is a specialized package for projects using <code>Microsoft.Extensions.*</code>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="140" class="wp-image-2783" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8-300x60.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8-50x10.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Open the <code>Startup.cs</code> file and add the mediator into the container, scanning the current assembly for all classes implementing <code>ICommandHandler</code>, <code>IQueryHandler</code> and <code>IEventHandler</code>:</p>



<pre class="wp-block-code"><code>services.AddMediator(o =&gt;
{
    o.AddHandlersFromAssemblyOf&lt;Startup&gt;();
});</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inject into the constructor the <code>IMediator</code> instance:</p>



<pre class="wp-block-code"><code>private readonly IMediator _mediator;
public ProductsController(IMediator mediator)
{
    _mediator = mediator;
}</code></pre>



<h1 class="wp-block-heading" id="a34c">The handlers</h1>



<p id="f409">We now have everything we need to start implementing the business logic.</p>



<p id="9537">To keep it simple, we are not going to use the mediator pipelines, only focusing on commands, queries, events and their handlers. I’ll demonstrate more complex scenarios in future articles.</p>



<p id="6baf">Start by creating a folder named <code>Handlers</code> with another inside <code>Products</code> in which we are going to put our POCOs and their handlers.</p>



<p id="b39b"><em>As a note, remember this is a demo article and this project structure </em><strong><em>should not be seen as a valid way to organize your solution</em></strong><em> in your private projects. Commands, queries, events and their handlers should be, at minimum, in different folders.</em></p>



<h2 class="wp-block-heading" id="998d">CreateProductComand</h2>



<p id="7eb1">We need data so lets create a command that allows that and will be sent when a request for POST /products is received.</p>



<p id="102f">Create a class <code>CreateProductResult</code> that will be returned by the handler with the product unique identifier and a <code>CreateProductCommand</code>, implementing the class <code>Command&lt;CreateProductResult&gt;</code>:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommand : Command&lt;CreateProductResult&gt;
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreateProductResult
    {
        public Guid Id { get; set; }
    }</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inside the method <code>CreateAsync</code> send the command into the mediator and map its result:</p>



<pre class="wp-block-code"><code>[HttpPost]
public async Task&lt;CreateProductResultModel&gt; CreateAsync([FromBody] CreateProductModel model, CancellationToken ct)
{
    var result = await _mediator.SendAsync(new CreateProductCommand
    {
        Code = model.Code,
        Name = model.Name,
        Price = model.Price
    }, ct);
    return new CreateProductResultModel
    {
        Id = result.Id
    };
}</code></pre>



<p id="f2ac">If we now invoked the endpoint, we would receive an exception saying that no <code>ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;</code> was found by the container.</p>



<p id="5fc5">We will fix that by creating the class <code>CreateProductCommandHandler</code> with the business logic for this action. For this demo, an <code>InvalidOperationException</code> with a custom message will be thrown when a duplicated code is received:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommandHandler : ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;
    {
        private readonly ApiDbContext _context;

        public CreateProductCommandHandler(ApiDbContext context)
        {
            _context = context;
        }

        public async Task&lt;CreateProductResult&gt; HandleAsync(CreateProductCommand cmd, CancellationToken ct)
        {
            var products = _context.Set&lt;ProductEntity&gt;();

            if (await products.AnyAsync(p =&gt; p.Code == cmd.Code, ct))
            {
                throw new InvalidOperationException($"Product code '{cmd.Code}' already exists");
            }

            var externalId = Guid.NewGuid();
            await products.AddAsync(new ProductEntity
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            await _context.SaveChangesAsync(ct);

            return new CreateProductResult
            {
                Id = externalId
            };
        }
    }</code></pre>



<p id="0a2d">If you now try to create a product using the Swagger endpoint, you will receive the response with the unique identifier or an internal server error indicating a duplicated code.</p>



<p id="2987">The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="320" height="422" class="wp-image-2784" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9.png 320w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9-227x300.png 227w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9-38x50.png 38w" sizes="(max-width: 320px) 100vw, 320px" /></figure>



<h2 class="wp-block-heading" id="4c1e">GetProductByIdQuery</h2>



<p id="b808">Time to return a product when a GET /products/:id is received by the web API.</p>



<p id="2303">Inside the <code>Handlers/Products</code> folder, create a <code>Product</code>, the <code>GetProductByIdQuery</code> and its corresponding handler, <code>GetProductByIdQueryHandler</code>. Like in the previous handler, for this demo, we are going to throw an <code>InvalidOperationException</code> if the id is unknown:</p>



<pre class="wp-block-code"><code>    public class GetProductByIdQuery : Query&lt;Product&gt;
    {
        public Guid ProductId { get; set; }
    }

    public class Product
    {
        public Guid Id { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class GetProductByIdQueryHandler : IQueryHandler&lt;GetProductByIdQuery, Product&gt;
    {
        private readonly IQueryable&lt;ProductEntity&gt; _products;

        public GetProductByIdQueryHandler(ApiDbContext context)
        {
            _products = context.Set&lt;ProductEntity&gt;();
        }

        public async Task&lt;Product&gt; HandleAsync(GetProductByIdQuery query, CancellationToken ct)
        {
            var product = await _products.SingleOrDefaultAsync(p =&gt; p.ExternalId == query.ProductId, ct);

            if (product == null)
            {
                throw new InvalidOperationException($"Product '{query.ProductId}' not found");
            }

            return new Product
            {
                Id = product.ExternalId,
                Code = product.Code,
                Name = product.Name,
                Price = product.Price
            };
        }
    }</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inside the method <code>GetByIdAsync</code> fetch the query from the mediator and map its result:.</p>



<pre class="wp-block-code"><code>[HttpGet("{id:guid}")]
public async Task&lt;ProductModel&gt; GetByIdAsync([FromRoute] Guid id, CancellationToken ct)
{
    var result = await _mediator.FetchAsync(new GetProductByIdQuery
    {
        ProductId = id
    }, ct);
    return new ProductModel
    {
        Id = result.Id,
        Code = result.Code,
        Name = result.Name,
        Price = result.Price
    };
}</code></pre>



<p id="a987">If you now try to get a product using the Swagger endpoint, you will receive the product or an internal server error indicating an unknown identifier.</p>



<h2 class="wp-block-heading" id="1f12">CreatedProductEvent</h2>



<p id="3451">Finally, we are going to create an event that will be broadcast when a product is successfully created.</p>



<p id="eae3">Just like the previous ones, create a <code>CreateProductEvent</code> and the handler <code>CreateProductEventHandler</code>. This time we are just going to log that a product was created:</p>



<pre class="wp-block-code"><code>    public class CreatedProductEvent : Event
    {
        public Guid ExternalId { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreatedProductEventHandler : IEventHandler&lt;CreatedProductEvent&gt;
    {
        private readonly ILogger&lt;CreatedProductEventHandler&gt; _logger;

        public CreatedProductEventHandler(ILogger&lt;CreatedProductEventHandler&gt; logger)
        {
            _logger = logger;
        }

        public Task HandleAsync(CreatedProductEvent evt, CancellationToken ct)
        {
            _logger.LogInformation("The product '{externalId}' has been created", evt.ExternalId);

            return Task.CompletedTask;
        }
    }</code></pre>



<p>Open the <code>CreateProductCommandHandler</code> file, inject the <code>IMediator</code> instance and after saving the changes just broadcast the event:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommandHandler : ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;
    {
        private readonly ApiDbContext _context;
        private readonly IMediator _mediator;

        public CreateProductCommandHandler(ApiDbContext context, IMediator mediator)
        {
            _context = context;
            _mediator = mediator;
        }

        public async Task&lt;CreateProductResult&gt; HandleAsync(CreateProductCommand cmd, CancellationToken ct)
        {
            var products = _context.Set&lt;ProductEntity&gt;();

            if (await products.AnyAsync(p =&gt; p.Code == cmd.Code, ct))
            {
                throw new InvalidOperationException($"Product code '{cmd.Code}' already exists");
            }

            var externalId = Guid.NewGuid();
            await products.AddAsync(new ProductEntity
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            await _context.SaveChangesAsync(ct);

            await _mediator.BroadcastAsync(new CreatedProductEvent
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            return new CreateProductResult
            {
                Id = externalId
            };
        }
    }</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="335" height="517" class="wp-image-2785" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10.png 335w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10-194x300.png 194w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10-32x50.png 32w" sizes="(max-width: 335px) 100vw, 335px" /></figure>



<h1 class="wp-block-heading" id="73e9">Conclusion</h1>



<p id="6b22">I hope this article gave you a good idea on how to use the mediator to implement the <strong>CQRS</strong> and <strong>ES</strong> patterns even if you are implementing an <strong>MVP</strong> and can’t spend much time thinking about the architecture but you still want something that can be maintained and extended for some time.</p>



<p id="f569">Soon I’ll be explaining more advanced scenarios, like using the mediator pipeline to validate commands before reaching the handler, managing database transactions or even implementing transversal auditing into you application.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
