X

ASP.NET Core Identity scaffolding

ASP.NET Core 2.1 introduces Razor UI class libraries that allow us to share UI artifacts with libraries and NuGet packages. One of first official packages delivered with UI pieces is ASP.NET Core Identity. This blog post shows how to override default views of ASP.NET Core Identity by using scaffolding.

Let’s start with ASP.NET Core 2.1 application that uses individual accounts for users.

ASP.NET Core Identity as Razor UI library

When taking a look at project structure we see that there’s no folder for identity related views. This is because views are packaged to ASP.NET Code Identity library. There’s only _ViewStart.cshtml file that applies default layout page to all views in identity area.

With ASP.NET Core Identity library we get default views and controllers. These things are packed to library and we don’t have any chance to make any modifications there. By example, we may want to add more fields to user profile and we want these fields to be filled when user joins our site.

What we can do is override controllers and UI artifacts in ASP.NET Core Identity library and for this we can use ASP.NET Core Identity scaffolding.

For this we right-click on project, select Add and then  New Scaffolded Item and Identity like shown on the following screenshots.

When clicking on Add button we can choose what artifacts we want to override.

And now comes a little surprise – although we have ASP.NET Core MVC application, we get, well…., overridden Razor pages.

I actually don’t want it to be about Razor Pages but here we are and it’s up to us to find also something good. Okay… pages at least have code-behind files and we don’t have to mess with C# code written straight to Razor Pages.

Digging around in identity libraries

Let’s take a look at code-behind file of DownloadPersonalData page that was generated by identity scaffolding.

public class DownloadPersonalDataModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ILogger<DownloadPersonalDataModel> _logger;

    public DownloadPersonalDataModel(
        UserManager<IdentityUser> userManager,
        ILogger<DownloadPersonalDataModel> logger)
    {
        _userManager = userManager;
        _logger = logger;
    }

    public async Task<IActionResult> OnPostAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        _logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User));

        // Only include personal data for download
        var personalData = new Dictionary<string, string>();
        var personalDataProps = typeof(IdentityUser).GetProperties().Where(
                        prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
        foreach (var p in personalDataProps)
        {
            personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
        }

        Response.Headers.Add("Content-Disposition", "attachment; filename=PersonalData.json");
        return new FileContentResult(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(personalData)), "text/json");
    }
}

Services are injected, that’s nice. But code-behind class inherits from PageModel and if we are scaffolding only for changing something in a view, we have suddenly a new class that is overriding all future changes to code-behind class of identity. Why are things like this? It’s actually simple – for running web application views are actually compiled classes defined in Microsoft.AspNetCore.Identity.UI.Views library. This is how DownloadPersonalData page looks in decompiler.

DownloadPersonalDataModel is defined in Microsoft.AspNetCore.Identity.UI library and it is internal class so we cannot use it from our projects.

As we can see then the pieces of code from those libraries render pretty much useless for us and this why we scaffolding for overriding default views and code-behind classes.

Wrapping up

ASP.NET Core Identity 2.1 comes with Razor UI libraries for identity related views. If we are okay with default implementations then we can go what comes by default. If we want to change something related to identity UI we have to use identity scaffolding. Identity scaffolding creates us Razor pages with code.-behind classes and we can make changes we need. We cannot re-use views and models from identity libraries partially – we either use out-of-box ones or we override and get new ones. New ones are in no way related to those in identity UI libraries.

Liked this post? Empower your friends by sharing it!
Categories: ASP.NET

View Comments (4)

  • Hi, thanks for this guide. Have you experience any redirects to HTTP away from HTTPS when user is not logged in?

    Im having that issue right now.

  • I have had no problems with redirects but I have used identity only in projects that anyway to HTTPS site. Make sure you have automatic redirects from HTTP to HTTPS enabled in application Startup. Maybe it helps.

  • Okay, thanks. The UseHttpsRedirection isn't helping in my case (even when its initiated as the first).

  • Try to spot out where the direct is actually made. If you used identity scaffolding then you have all controller actions under your control. Can you find the action where redirect is made or is it happening when returning from some social auth provider (FB, Twitter, etc)?

Related Post