1

Similar questions have been posted before (1, 2, 3), but the situation is different.

I have an .Net Core 7 app using EFCore with some existing entities. Now that everything in there is tested and working, I'd like to add the Identity functionality and then link AspNetUsers to a couple of my existing entities.

Currently there are no identity tables, nor any sort of tables used by the Identity functionality.

Using the Microsoft tutorial Scaffold Identity into a Razor project without existing authorization I get to the step whereby I need to specify my database and user contexts.

After unsuccessfully looking for documentation I entered the database context as being the one which is used in my data project ('EventFinderData' below - a different project to my web app, but within the same solution). I then created a new user context...

enter image description here

After the scaffolding is complete, I get a number of ambiguous reference errors as the scaffolding process creates a new data context:

// This is a duplicate class of that within the EventFinderData project, which is already referenced within my web app
public class EventFinderContext : IdentityDbContext<EventFinderWebAppRazorUser> 
{
    public EventFinderContext(DbContextOptions<EventFinderContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}

I tried to make both classes partial, but then when I add a migration I get:

More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands.

Some experts seem to recommend starting a new project with Identity included already, and building out from there, but its going to be a big job.

  1. What do I need to modify please in order for this scaffolding process to bolt into my existing EFCore logic?
  2. Alternatively is Identity supposed to use a dedicated (separate) context? That would seem unintuitive given the tables need relationships between identity entities and my existing entities.

Update

Based on suggestions, here are the three classes I get after adding the Identity functionality:

Data project (containing Entities and migrations):

EventFinderContext.cs

namespace EventFinderData
{
    public class EventFinderContext : DbContext
    {
        public DbSet<EventItem> EventItems { get; set; }
        public DbSet<EventCategory> EventCategories { get; set; }

        public EventFinderContext(DbContextOptions<EventFinderContext> options) : base(options) 
        {
        }

    }
}

Web app project - Classes created by VS/Identity

Areas\Identity\Data\EventFinderWebAppRazorContext.cs

namespace EventFinderWebAppRazor.Data;
public class EventFinderWebAppRazorContext : IdentityDbContext<EventFinderWebAppRazorUser>
{
    public EventFinderWebAppRazorContext(DbContextOptions<EventFinderWebAppRazorContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

Areas\Identity\Data\EventFinderWebAppRazorUser.cs

namespace EventFinderWebAppRazor.Areas.Identity.Data;

public class EventFinderWebAppRazorUser : IdentityUser
{
}

Program.cs

builder.Services.AddDbContextFactory<EventFinderContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("EventFinderConnString"), 
        ss => ss.UseNetTopologySuite())
    .EnableSensitiveDataLogging());

builder.Services.AddDefaultIdentity<EventFinderWebAppRazorUser>(
    options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<EventFinderWebAppRazorContext>();
Kit
  • 20,354
  • 4
  • 60
  • 103
EvilDr
  • 8,943
  • 14
  • 73
  • 133
  • 1
    Same here, I guess you need to implement Identity db context to your db context. but dont know how to do completely – Rapunzo Nov 13 '22 at 12:22
  • I've solved same problem by starting a new project with Identity included already. – Rapunzo Nov 15 '22 at 13:13
  • @Rapunzo doesn't that require all DB and context logic to be in one project (e.g. no domain-driven design, etc)? – EvilDr Nov 15 '22 at 13:35

1 Answers1

2

Not sure if something changed (.net6 here) but to add the dot net identity framework to your existing context all you have to do is just provide that context when adding it to the IServiceCollection.

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
})
.AddEntityFrameworkStores<ApplicationDbContext>()

You will need to change your DbContext so it inherits from

IdentityDbContext<ApplicationUser>

This will only provide the required services, not the different views and UX flows that comes when you scaffold it. So no login/logout, password resets, MFA setup etc...

I hope this will help.

Update

Based on the OP's update, the following updates are required.

Areas\Identity\Data\EventFinderWebAppRazorUser.cs

Move this class to your Data project. It will become a part of your own entity model. Make sure that the namespace is also updated. Although this is not really necessary, but it is nice to have all entities in the same namespace.

Areas\Identity\Data\EventFinderWebAppRazorContext.cs

Delete this file/class. This is the extra context created by the scaffolding process, but as we want to use our own context we don't need it.

EventFinderContext.cs

Update this class like below.

namespace EventFinderData
{
    public class EventFinderContext : IdentityDbContext<EventFinderWebAppRazorUser>
    {
        public DbSet<EventItem> EventItems { get; set; }
        public DbSet<EventCategory> EventCategories { get; set; }

        public EventFinderContext(DbContextOptions<EventFinderContext> options) : base(options) 
        {
        }

    }
}

Program.cs

Update this file like below. And make sure all types resolve by updating the usings.

builder.Services.AddDbContextFactory<EventFinderContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("EventFinderConnString"), 
        ss => ss.UseNetTopologySuite())
    .EnableSensitiveDataLogging());

builder.Services.AddDefaultIdentity<EventFinderWebAppRazorUser>(
    options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<EventFinderData.EventFinderContext>();
verbedr
  • 1,784
  • 1
  • 15
  • 18
  • How does this relate to my existing sample provided? Does it replace it completely? Where do I specify my new DBContext - in the web project or the data project? Does the new DbContext replace my existing context across the entire application? What file do I add your first sample to? – EvilDr Nov 15 '22 at 12:03
  • Remove the scaffold version and update your existing version, so that it inherits from "IdentityDbContext" and not from "DbContext". – verbedr Nov 15 '22 at 12:34
  • We're going to have to adopt layman's terms I'm afraid. I've rolled back the code base so there's no mention of Identity. Am I still using the Add > New Scaffolded item function? If so what do I enter into the fields, and does identity require a different dbcontext to that which already exists? – EvilDr Nov 15 '22 at 13:41
  • Yes, you can. For data context class, you can choose anything. It will generate this class, and the major difference with your existing dbcontext is the inheritance. Update your class with that information. (Most likely, replace ": DbContext" with ": IdentityDbContext".) In the start/program file, replace the reference to the generated context with your context ".AddEntityFrameworkStores<...this needs to be updated...>()". And that should be it. – verbedr Nov 15 '22 at 14:04
  • 1
    I tried my best and hope the answer is acceptable. – verbedr Nov 16 '22 at 20:42
  • Okay thanks. `EventFinderWebAppRazorUser.cs` has been moved to the data project, but now VS complains that `IdentityUser` can't be found in that project. From the VS suggestions, should I install `Microsoft.AspNetCore.Identity.EntityFrameworkCore` (my assumption), and/or the other suggestion of `Microsoft.Extensions.Entity.Stores`? – EvilDr Nov 17 '22 at 08:33
  • 1
    Yes both, you do want to merge the identity context with your own context? Then it will need the identity dependencies. – verbedr Nov 17 '22 at 08:42
  • BOOM! You got me there. After a bit of deleting unnecessary connection string settings the process had added, its worked. Thanks for sticking with me. Much appreciated. – EvilDr Nov 17 '22 at 10:14
  • Aside... please feel free to go rewrite **Microsoft's dreadful documentation** on this particular approach ;-) – EvilDr Nov 17 '22 at 10:15