question

JORGEMALDONADOBARRERA-7687 avatar image
0 Votes"
JORGEMALDONADOBARRERA-7687 asked ZhiLv-MSFT commented

Testing a ASP.NET 6 website project with 2 contexts

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

dotnet-aspnet-core-generaldotnet-entity-framework-core
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @JORGEMALDONADOBARRERA-7687,

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 still feel confused about your question. Since you have already configured two DBContext for the database(for example: Dbcontext1=> DB1, Dbcontext2=> DB2), when using them, just calling the DBcontext1 or Dbcontext2 in the application. From your desciption, do you mean you want to use different Dbcontext or DB between the production or development environments? If that is the case, you could configure the database based on the Environment, refer to this article: Use multiple environments in ASP.NET Core.

0 Votes 0 ·

Let´s first consider the Development Environment.

In my ASP.NET 6 MVC web project, I only use EF in the Identity section to be able to manage users and roles through UserManager, SignInManager and RoleManager classes because they are based on EF and it is required. Let´s suppose my project DBs only have the Identity tables and nothing else.

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.

Thanks in advance.

0 Votes 0 ·

1 Answer

ZhiLv-MSFT avatar image
0 Votes"
ZhiLv-MSFT answered ZhiLv-MSFT commented

Hi @JORGEMALDONADOBARRERA-7687,

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


image.png (115.7 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

It seems that your answer is an approach. However, it looks more complicated than I expected and I want to keep things as simple as possible. (Or my approach is complicated)

What would be your approach in a situation where one web project is going to be installed twice to host 2 websites (2 domains: www.d1.com and www.d2.com). Both domains will be accessing its own DB so there will be 2 DBs, but DBs have the exact same schema including Identity tables. If I have the project ready, should I "duplicate" it in my VS2022 and deploy each one separately? If I duplicate it, then I need to set its own connection strings for the corresponding DB and run its own add-migration and update-database commands. I am bit confused with this situation.

Regards.

0 Votes 0 ·
ZhiLv-MSFT avatar image ZhiLv-MSFT JORGEMALDONADOBARRERA-7687 ·

What would be your approach in a situation where one web project is going to be installed twice to host 2 websites (2 domains: www.d1.com and www.d2.com). Both domains will be accessing its own DB so there will be 2 DBs, but DBs have the exact same schema including Identity tables. If I have the project ready, should I "duplicate" it in my VS2022 and deploy each one separately? If I duplicate it, then I need to set its own connection strings for the corresponding DB and run its own add-migration and update-database commands. I am bit confused with this situation.

Since they use the same code, how about hosting the web project once and then configuring the site to use both domains? Refer Point multiple domains to one website on IIS7.

0 Votes 0 ·