Testing a ASP.NET 6 website project with 2 contexts

JORGE MALDONADO BARRERA 211 Reputation points
2022-05-19T15:38:45.71+00:00

Hi,

I am developing an ASP.NET 6 website in VS2022 with the following characteristics:

  • The website uses Identity for authentication.
  • The website will be installed (hosted) twice in one production server.
  • Each installation will point to its own domain name.
  • Each installation will have its own database.
  • Both databases have the exact same schema.
  • Databases will contain different data and different users.
  • Only Identity uses Entity Framework, the rest of the data operations to the DB do not use EF.
  • My local project has 2 connection strings.
  • There are 2 DBs in my local development PC.

My project has 2 Contexts and I already performed add-migration and update-database commands to create the Identity Tables for each one as shown below. So far, each DB has its own set of Identity Tables. Also, each DB has the tables that contain domain specific data (for example: customers and invoices).

  • add-migration -Name migration-name -OutputDir outputdir-path -Context context-name
  • update-database -Context context-name

I individually publish the project for both websites that will be hosted in the production server to a local folder and select the options accordingly which can be simplified creating a new profile for each case.

  • I select a specific connection string.
  • I select a specific Entity Framework Migration.

All this seems to be fine to publish each web site to the production server but, how do I work with each case (context or DB) separately in my local development project? For example, if I have DB1 and DB2, how do I tell my project to run and access DB1 and vice versa?

(I explained the whole situation to make clear what I am trying to achieve)

Respectfully,
Jorge Maldonado

Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
696 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,190 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Zhi Lv - MSFT 32,016 Reputation points Microsoft Vendor
    2022-05-25T08:47:25.293+00:00

    Hi @JORGE MALDONADO BARRERA ,

    If I have 2 DBs (with the exact same schema meaning each DB has only the Identity tables) and 2 Contexts (one for each DB), and I run the project to add users, for example, which DB will be used to insert such users? or How do I tell my project to add users to DB1 or DB2?

    Maybe this is a basic question but I am not a EF expert, I am using it only because it is required by Identity.

    Do you mean in your project, you want to use Asp.net core Identity with 2 Dbcontexts (one for each DB)? As far as I know, if add Identity twice, it will show the "InvalidOperationException: Scheme already exists: Identity.Application" error when running the application.

    So, to manage the Identity tables from two database, as a workaround, you can try to use Identity with the first or second DbContext, then for the other DbContext, you can directly access the related Identity tables via the DbContext, instead of via the Asp.net core Identity (using the UserManager or RoleManager).

    Code like this:
    Program.cs:

    //register two dbcontexts, one for each DB  
    var firstDbconnectionString = builder.Configuration.GetConnectionString("FirstDbConnection");  
    var secondDbconnectionString = builder.Configuration.GetConnectionString("SecondDbConnection");  
    builder.Services.AddDbContext<FirstDbContext>(options =>  
        options.UseSqlServer(firstDbconnectionString));  
    builder.Services.AddDbContext<SecondDbContext>(options =>  
        options.UseSqlServer(secondDbconnectionString));  
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();  
      
    //select one dbContext and confire the Identity.  
    builder.Services.AddDefaultIdentity<FirstDbAppUser>(options => options.SignIn.RequireConfirmedAccount = true)  
        .AddEntityFrameworkStores<FirstDbContext>();  
    

    When use the Identity and SecondDbContext, the code like this:

    Register.cshtml.cs:

    public class RegisterModel : PageModel  
    {  
        //Use Identity with First DBContext.  
        private readonly SignInManager<FirstDbAppUser> _firstDbsignInManager;  
        private readonly UserManager<FirstDbAppUser> _firstDbuserManager;  
        private readonly IUserStore<FirstDbAppUser> _firstDbuserStore;  
        private readonly IUserEmailStore<FirstDbAppUser> _firstDbemailStore;  
        private readonly ILogger<RegisterModel> _logger;  
        private readonly IEmailSender _emailSender;  
           
        #region  
        //use the second DbContext.  
        private readonly SecondDbContext _senddbcontext;   
        private readonly IPasswordHasher<FirstDbAppUser> _passwordHasher;  
        #endregion  
        public RegisterModel(  
            UserManager<FirstDbAppUser> userManager,  
            IUserStore<FirstDbAppUser> userStore,  
            SignInManager<FirstDbAppUser> signInManager,  
            ILogger<RegisterModel> logger,  
            SecondDbContext secondDbContext,  
            IPasswordHasher<FirstDbAppUser> passwordHasher,  
            IEmailSender emailSender)  
        {  
            _firstDbuserManager = userManager;  
            _firstDbuserStore = userStore;  
            _firstDbemailStore = GetEmailStore();  
            _firstDbsignInManager = signInManager;  
            _logger = logger;  
            _emailSender = emailSender;  
            _senddbcontext = secondDbContext;  
            _passwordHasher = passwordHasher;  
        }  
    

    and

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)  
        {  
            returnUrl ??= Url.Content("~/");  
            ExternalLogins = (await _firstDbsignInManager.GetExternalAuthenticationSchemesAsync()).ToList();  
            if (ModelState.IsValid)  
            {  
                var user = CreateUser();  
    
                await _firstDbuserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);  
                await _firstDbemailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);   
                //Create user in the SecondDb using SecondDbContext.  
                _senddbcontext.Users.Add(new SecondDbAppUser() { UserName = user.UserName, PasswordHash = _passwordHasher.HashPassword(user, Input.Password) });  
                _senddbcontext.SaveChanges();  
     
                //create user in the FirstDb using Identity.  
                var result = await _firstDbuserManager.CreateAsync(user, Input.Password);  
     
                if (result.Succeeded)  
                {  
                      ...  
    

    Then, after register an new user the result like this:

    205423-image.png


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion