0

I have two databases. When first started the solution will check for databases and then create them via a migration. The migrations for both DB's exist however when called to create the context from startup its actually going to the wrong service and I dont know why.

Here is the code that is, among other things creating the context.

public static class StartupCATALOGExtension
{
    public static void EnsureCATALOGMigrationAndInitialise(this IApplicationBuilder app)
    {
        if (app == null) throw new ArgumentNullException(nameof(app));

        using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetService<CATALOGContext>();
            var cryptoService = serviceScope.ServiceProvider.GetService<ICryptoService>();

            context.Database.Migrate();
            serviceScope.ServiceProvider.GetService<ICATALOGCounterInitialiser>()
                .InitialiseCATALOGCounters(context);
            serviceScope.ServiceProvider.GetService<ICATALOGStateInitialiser>().CATALOGInitialiseStates(context);
            serviceScope.ServiceProvider.GetService<ICATALOGSuburbInitialiser>().CATALOGInitialiseSuburbs(context);
            serviceScope.ServiceProvider.GetService<IRoleInitialiser>().InitialiseRoles(context);
            serviceScope.ServiceProvider.GetService<ITenantAndUserInitialisations>()
                .InitialiseTenantsAndUsers(context, cryptoService);
        }
    }
}

}

I can step my way down to this line:

var context = serviceScope.ServiceProvider.GetService<CATALOGContext>();

At which point it goes off to the Startup.cs file and in particular the services section. I have this there:

        services
            // Add framework services.
            .AddOptions()

            .AddDbContext<CATALOGContext>(options => options
                .UseSqlServer(Configuration
                    .GetConnectionString("CatalogConnection"), b => b.MigrationsAssembly("JobsLedger.CATALOG")))

            .AddDbContext<DATAContext>(options => options
                .UseSqlServer(Configuration
                    .GetConnectionString("TenantDbConnection"), a => a.MigrationsAssembly("JobsLedger.DATA")))

Its suppose to go specifically to:

            .AddDbContext<CATALOGContext>(options => options
                .UseSqlServer(Configuration
                    .GetConnectionString("CatalogConnection"), b => b.MigrationsAssembly("JobsLedger.CATALOG")))

However for whatever reason that I cannot fathom its going to the other service...

            .AddDbContext<DATAContext>(options => options
                .UseSqlServer(Configuration
                    .GetConnectionString("TenantDbConnection"), a => a.MigrationsAssembly("JobsLedger.DATA")))

I have no idea why it would jump right past the service its suppose to go to and end up with the other database's service..

Why is is going to the second service and more importantly how do you make it go to the correct service?

EXTRA INFO

For completeness here are the connection strings in my appsettings file:

"ConnectionStrings": {
    "CatalogConnection": "Server=(localdb)\\mssqllocaldb;Database=catalogDb;Trusted_Connection=True;MultipleActiveResultSets=true",
    "TenantDbConnection": "Server=(localdb)\\mssqllocaldb;Database=masterDb;Trusted_Connection=True;MultipleActiveResultSets=true"
},

and here is the migrations file:

using JobsLedger.AUTHORISATION.API.SessionMiddleware;
using JobsLedger.CATALOG;
using JobsLedger.DATA;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace JobsLedger.API {
    public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<CATALOGContext> {
        public CATALOGContext CreateDbContext(string[] args) {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

            var builder = new DbContextOptionsBuilder<CATALOGContext>();

            var userSession = new UserSession {
                ConnectionString = configuration.GetConnectionString("CatalogConnection")
            };

            builder.UseSqlServer(userSession.ConnectionString);

            return new CATALOGContext(builder.Options, userSession);
        }
    }
}
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<DATAContext> {
    public DATAContext CreateDbContext(string[] args) {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

        var builder = new DbContextOptionsBuilder<DATAContext>();

        var userSession = new UserSession {
            ConnectionString = configuration.GetConnectionString("TenantDbConnection")
        };
        return new DATAContext(builder.Options, userSession);
    }
}
1
  • Anybody have an idea on this.. its literally selecting the other database for what ever reason. Commented Jan 29, 2020 at 12:12

1 Answer 1

1

Well with the overwhelming interest in this question I did a bit of research tonight.

I loaded the actual error - at least the last part and I found THIS post response by Rowan Miller.

Essentially I needed to use a generic options type. So, I changed my constructor in each DbContext to reflect what it actually is..

For my CATALOGContext I changed from this:

public CATALOGContext(DbContextOptions options, IUserSession userSession) : base(options)
        {
            _userSession = userSession;
        }

To this:

public CATALOGContext(DbContextOptions<CATALOGContext> options, IUserSession userSession) : base(options)
        {
            _userSession = userSession;
        }

..and now it chooses the right context to use.

Sign up to request clarification or add additional context in comments.

1 Comment

I had something a bit similar, except I was registering the same context against two different interfaces so I could have two different lifetimes (one Scoped for normal REST operations, and one Transient for use in various background services, which allowed those services to take control of the lifetime of their context instance to recover from db connection problems and allow dynamically changing the DB path etc. without restarting the app). I was confused as to why I was getting the wrong context and swapping the registration order would change which one... your answer helped, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.