<?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>dotnet core &#8211; ASP.NET Hosting Reviews and Guides</title>
	<atom:link href="https://topreviewhostingasp.net/tag/dotnet-core/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>dotnet core &#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>
	</channel>
</rss>
