EF6 CLI tooling unable to read connection string from user secrets .net core

489 Views Asked by At

We have a legacy system that utilises EF6. Like many, we have made the move to .Net Core but have found EFCore to be somewhat lacking in all of the functionality we require within our existing system. With this in mind, we are currently using EF6 inside our .Net core solution.

Until now, our newer, .Net Core based systems have only had read and write privileges to our existing database, sharing entity configuration with an older .Net framework solution. Our existing process relies upon the .Net Framework application applying migration changes to the database. Our .Net core application is then able to interact with the database by sharing the entities and configuration to with the .Net framework project. This has worked well for us so far, however, we now require the ability to apply migrations from a new .Net core project to a new database.

We make heavy use of some of the new features of .Net core including the use of user secrets but we are finding that this is causing issues when we try and apply migrations to a local database during development as this seems to always default to local DB when we use the EF6 CLI tools via the package manager console.

We have created a simple context factory that takes in app settings via the options pattern and uses the value within to pass the connection string into the context upon creation, however, when running the EF6 CLI tools the options are always null.

public class MyContextFactory : IDbContextFactory<MyContext>
{
    private readonly IOptions<ConnectionStrings> _settings;

    public MyContextFactory(IOptions<ConnectionStrings> settings)
    {
        _settings = settings;
    }

    public MyContext Create()
    {
        return new MyContext(_settings.Value.MyConnectionString);
    }
}

I believe this is because the EF6 tools only run the context factory class but this is not being done with development environment settings applied and therefore when retrieving the options it comes back empty because the related json field in our appsettings is blank (this is by our development convention as we never save secrets into our repos).

To test this theory, I added our connection string directly into app settings. Whilst this did not produce the null reference exception error we were receiving before, it did produce a new error regarding the lack of a parameterless constructor:

The context factory type 'MyProject.Data.Ef6.Context.MyContextFactory' does not have a public parameterless constructor. Either add a public parameterless constructor, create an IDbContextFactory implementation in the context assembly, or register a context factory using DbConfiguration.

If I add in a parameterless constructor though I am presented with the same

Object reference not set to an instance of an object.

error as before.

EFCore is not an option, so how might we adapt our project so that we can perform local database migrations without having to hard-code any connection strings within our context factory or our context itself?

We are not too concerned with our production environments as we manually apply up and down migrations to these so will have automatic migrations turned off but we want to set this up in a way that prevents developers from accidentally committing our connection strings into the codebase.

Thanks in advance.

I can provide any further information required.

Edit:

Context is setup in startup.cs as follows:

services.AddTransient<IVehicleLookupContext>(_ => new MyContext(Configuration.GetConnectionString("MyConnectionString")));

Options are setup in startup.cs as follows:

services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));

Connection string is stored in appsettings.json but is blank in the repo. It is populated solely by usersecrets on the users machine so that no connection strings are written to the repo.

0

There are 0 best solutions below