Entity Framework 7 Migration Scaffolding in Class Library with Configuration - entity-framework-migrations

Trying to add migrations to an EF7 Model that lives in an ASP.NET 5 class library. When running dnx . ef migration add mymigration fails with different results depending on which project I run it on.
If I run it in the folder of the main project, it cannot locate a DbContext, this makes sense because the DbContext is in the shared project and ef commands likely don't care about dependencies.
If I run it in the folder of the shared project, it does not have access to the connection string specified in the startup.cs. I have gleaned from questions like this that it does work from the shared project if you specify the connection string in the OnConfiguring method of the DbContext but I really would like to keep this code separate from the configuration.
I came across some issue logs in the EF7 repository that mention they implemented command line options for specifying a project and a context but there are no examples and I couldn't figure out how to use it from looking at the source code in the commit history.

Here is an approach that might work for you.
If I run it in the folder of the shared project, it does not have access to the connection string specified in the startup.cs.
Startup.cs
I'm assuming that in your Startup.cs, you're specifying the connection string by accessing Configuration rather than by hard coding it. Further, I'm assuming that in your Startup.cs file's constructor, you're setting up configuration from a few sources. In other words, your Startup.cs might look something like this:
public class Startup
{
public IConfiguration Config { get; set; }
public Startup(IHostingEnvironment env)
{
var config = new Configuration()
.AddJsonFile("config.json")
.AddUserSecrets()
.AddEnvironmentVariables();
Config = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer(Config["ConnectionStrings:MyDbContext"]);
});
}
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
var db = serviceProvider.GetRequiredService<MyDbContext>();
db.Database.AsSqlServer().EnsureCreated();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
config.json
Further, I'm assuming that you're adding the connection string to a config.json in the root of your project (or that you adding it via user secrets or environmental variables.) Your config.json might look something like this:
{
"ConnectionStrings": {
"MyDbContext": "Some-Connection-String"
}
}
If you're not doing it that way, it might be worth trying it.
I have gleaned from questions like this that it does work from the shared project if you specify the connection string in the OnConfiguring method of the DbContext but I really would like to keep this code separate from the configuration.
DbContext
If my assumptions above are correct, then you can access the connection string in the DbContext by using the same pattern that you used in the Startup class. That is, in the DbContext constructor, setup the IConfiguration. Then, in OnConfiguring, access the connection string. It might look something like this:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<SomeModel>().Key(e => e.Id);
base.OnModelCreating(builder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connString = Config["ConnectionStrings:MyDbContext"];
optionsBuilder.UseSqlServer(connString);
}
public IConfiguration Config { get; set; }
public MyDbContext()
{
var config = new Configuration()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
Config = config;
}
}
Project Structure
You'll of course need to have a config.json file in the root of your shared projects folder too. So, your projects' structure could look something like this:
SharedDataContext
Migrations
config.json
project.json
WebApp
config.json
project.json
Startup.cs
In the above, both config.json files contain a connection string setting for the DbContext.
Some Thoughts
If you don't like duplicating the config.json connection string stuff, then you can use environmental variables or user secrets instead.

Related

Entity Framework Core Error: No parameterless constructor defined for this object

At the point of creating a new MVC Controller:
after I click Add button, I get the following Error:
Here is my simple Context class:
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
and my simple model:
public partial class Todo
{
public int Id { get; set; }
public string TaskName { get; set; }
}
I have made some search on this issue, most of the posts point to a dropdown list or a SelectList method using MVC, but for my case it is a Controller creation fail, so it seems to be an Entity Framework Core issue
Any help ?
Thanks to #poke comment above, and to this link: "Use Code First with connection by convention", by modifying the context class as follows C# will call base class parameterless constructor by default
public class MainDbContext : DbContext
{
public MainDbContext()
// C# will call base class parameterless constructor by default
{
}
}
It's a tooling error. Most likely, you're running Visual Studio 2015, which doesn't have full .NET Core support. Basically, in previous versions of EF, DbContext had a parameterless constructor, and this version of the scaffold generator is depending on that. In EF Core, DbContext does not have a parameterless constructor, so the generator is choking on that.
If you're using VS2015, upgrade to 2017. It's time. Aside from that, you don't need this anyways, and it's only leading you down a bad path. All the scaffold does is create a new class under Controller, named {Name}Controller that inherits from Controller. Then it creates a folder named {Name} in Views and adds some basic HTML for doing CRUD. You'll end up replacing most of this HTML anyways. Additionally, the scaffold requires you to work with an actual entity class, which is the last thing you should ever be doing. You should always accept user input via a view model and then map that posted data onto your entity class before finally saving the entity. Look at the scaffold being broken as an excellent opportunity to start learning how to create good code.
Here's the solution from Microsoft. It suggest to create a design-time class that instantiates the connection to a database.
A solution
Because DbContext constructor is expecting DbContextOptions, AddDbContext must be set within the Startup Configuration method.
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
Within projects startup.cs set AddDbContext
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
ConfigureServices method:
Set database:
UseSqlServer,
UseInMemeoryDatabase,
UseSqlite,
etc...
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
}
Make sure your project builds and runs without errors before scaffolding.
In Visual Studio 2019, I received this error while attempting to scaffold a new controller because I had a missing comma in my JSON in appsettings.json file.
Eventually I built and tried to run and got a System.FormatException, "Could not parse the JSON file" during runtime.
Since appsettings.json was the only JSON file I was editing recently I knew it had to be appsettings.json.
Scaffolding, code generators, and EF migrations invoke runtime code, this means even if your code compiles, if it throws runtime errors those could cause a problem for such actions.
FYI -
As of EF Core 2.1 parameterized constructors are allowed.
See this Microsoft article for more information.
https://learn.microsoft.com/en-us/ef/core/modeling/constructors
the solution is check the file Startup.cs if you have in the void ConfigureServices the DataContext, for example in SQLServer my Startup.cs is
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourDataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("YourConnectionStrings")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
if you not have this services the error is
no parameterless constructor defined for type YourDataContextName
I had the same problem and I add this line to Startup.cs on the ConfigureServices method.
It worked fine for me:
services.AddControllersWithViews();
Just add an empty constructor to your dbcontext and this solves the problem.

Injecting Different Implementations of Same Interface in ASP.NET 5

In ASP.NET 5, I have an IRepository interface that I used to access some databases, like this:
public interface IRepository {
IQueryable<T> QueryItems(string sql);
}
public class Repository : IRepository {
private readonly string ConnectionString;
public Repository(string connStr) {
// Save the injected connection string
this.ConnectionString = connStr;
}
public IQueryable<T> QueryItems(string sql) {
// Implementation ignored here
}
}
In my Startup.cs class, I am registering the IoC/DI like this:
services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));
That all works fine if I only have one connection string. However, how can I register and subsequently inject the correct IRepository if I use the Repository to connect to 2+ different databases with different connection strings?
services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));
services.AddTransient<IRepository>(s => new Repository("DIFFERENT_CONNSTR"));
In older IoC/DI systems, I would have use "named" implementations that could be resolved with something like a [Dependency("DUMMY")] attribute on the constructor parameter.
Any help would be appreciated.
There are a few approach that you can take one is to inject a factory and base on the specific criteria you can produce a repository, the other approach is use a Dispatcher that also produce the repository base on the criteria, below is a question that I ask with the same problem. The question below have both approach but they were codding a beta version of .net core
See this question for reference and code
You can substitute StructureMap or Autofac for the default DI container (see my blog post for detailed instructions). Both support "named" interface registration (StructureMap named instances and Autofac named and keyed services).
Additionally, if you target dnx451, you can use Autofac's WithKey attribute. Using the Visual Studio sample project from the blog post, add the following dependency in project.json:
"frameworks": {
"dnx451": {
"dependencies": {
"Autofac.Extras.AttributeMetadata": "4.0.0"
}
}
},
Given a test class with the following constructor:
public MyClass([WithKey("logging")] IRepository repository)
{
Repository = repository;
}
you would register everything in ConfigureServices (note the use of WithAttributeFilter():
containerBuilder.Register(c => new Repository("DEFAULT_CONNSTR")).Keyed<IRepository>("default");
containerBuilder.Register(c => new Repository("LOGGING_CONNSTR")).Keyed<IRepository>("logging");
containerBuilder.RegisterType<MyClass>().WithAttributeFilter();

No default Instance is registered and cannot be automatically determined for type

The definition of my interface is as follows:
public interface IApplicationSettings
{
string LoggerName { get; }
string NumberOfResultsPerPage { get; }
string EmailAddress { get; }
string Credential { get; }
}
The implementation of this interface is given below:
public class WebConfigApplicationSettings : IApplicationSettings
{
public string LoggerName
{
get { return ConfigurationManager.AppSettings["LoggerName"]; }
}
public string NumberOfResultsPerPage
{
get { return ConfigurationManager.AppSettings["NumberOfResultsPerPage"]; }
}
public string EmailAddress
{
get { return ConfigurationManager.AppSettings["EmailAddress"]; }
}
public string Credential
{
get { return ConfigurationManager.AppSettings["Credential"]; }
}
}
I also created a factory class to obtain the instance of the concrete implementation of WebConfigSettings as follows:
public class ApplicationSettingsFactory
{
private static IApplicationSettings _applicationSettings;
public static void InitializeApplicationSettingsFactory(
IApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
public static IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
Then I resolved dependency as follows:
public class DefaultRegistry : Registry {
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
}
}
Now when i running my application it throw me following exception:
Exception has been thrown by the target of an invocation.
and the Inner Exception is
No default Instance is registered and cannot be automatically determined for type 'Shoppingcart.Infrastructure.Configuration.IApplicationSettings'\r\n\r\nThere is no configuration specified for Shoppingcart.Infrastructure.Configuration.IApplicationSettings\r\n\r\n1.) Container.GetInstance(Shoppingcart.Infrastructure.Configuration.IApplicationSettings)\r\n
I am using StructureMap for MVC5
The reason your code isn't working is because when you call ObjectFactory.GetInstance<IApplicationSettings>(), your registry hasn't been registered and thus, StructureMap's configuration is incomplete.
I believe what you're trying to do is the following (tested and works):
public class ApplicationSettingsFactory
{
public ApplicationSettingsFactory(WebConfigApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
private static IApplicationSettings _applicationSettings;
public IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
With your registry configured like this:
public DefaultRegistry() {
Scan(scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
this.For<IApplicationSettings>().Use(ctx => ctx.GetInstance<ApplicationSettingsFactory>().GetApplicationSettings());
}
I can't really tell you why your registration fails in StructureMap, but if you allow me, I would like to feedback on your design.
Your design and code violates a few basic principles:
You are violating the Interface Segregation Princple (ISP).
The ISP describes that interfaces should be narrow (role interfaces) and should not contain more members than a consumer uses. You however defined an application wide IApplicationSettings interface and your intention is to inject into any consumer that needs some configuration settings. Changes are really slim however that there is a consumer that actually needs all settings. This forces the consumer to depend on all members, it makes the API more complex, while it just needs one.
You are violating the Open/Closed Principle (OCP).
The OCP describes that it should be possible to add new features without making changes to existing classes in the code base. You will however find yourself updating the IApplicationSettings interface and its implementations (you will probably have a fake/mock implementation as well) every time a new setting is added.
Configuration values aren't read at startup, which makes it harder to verify the application's configuration.
When a consumer makes a call to a property of your IApplicationSettings abstraction, you are forwarding the call to the ConfigurationManager.AppSettings. This means that if the value isn't available or incorrectly formatted, the application will fail at runtime. Since some of your configuration values will only be used in certain cases, this forces you to test every such case after you deployed the application to find out whether the system is configured correctly.
Solution
The solution to these problems is actually quite simple:
Load configuration values at start-up.
Inject configuration values directly into a component that needs that exact value.
Loading the configuration values directly at start-up, allows the application to fail fast in case of a configuration error, and prevents the configuration from being read over and over again needlessly.
Injecting configuration values directly into a component, prevents that component from having to depend on an ever-changing interface. It makes it really clear what a component is depending upon, and bakes this information in during application start-up.
This doesn't mean though that you can't use some sort of ApplicationSettings DTO. Such DTO is exactly what I use in my applications. This basically looks as follows:
public static Container Bootstrap() {
return Bootstrap(new ApplicationSettings
{
LoggerName = ConfigurationManager.AppSettings["LoggerName"],
NumberOfResultsPerPage = int.Parse(
ConfigurationManager.AppSettings["NumberOfResultsPerPage"]),
EmailAddress = new MailAddres(
ConfigurationManager.AppSettings["EmailAddress"]),
Credential = ConfigurationManager.AppSettings["Credential"],
});
}
public static Container Bootstrap(ApplicationSettings settings) {
var container = new Container();
container.RegisterSingle<ILogger>(
new SmtpLogger(settings.LoggerName, settings.EmailAddress));
container.RegisterSingle<IPagingProvider>(
new PagingProvider(settings.NumberOfResultsPerPage));
// Etc
return container;
}
In the code above you'll see that the creation of the ApplicationSettings DTO is split from the configuration of the container. This way I can test my DI configuration inside an integration test, where the start-up projects configuration file is not available.
Also note that I supply the configuration values directly to the constructors of components that require it.
You might be skeptic, because it might seem to pollute your DI configuration, because you have dozens of objects that require to be set with the same configuration value. For instance, your application might have dozens of repositories and each repository needs a connection string.
But my experience is that is you have many components that need the same configuration value; you are missing an abstraction. But don't create an IConnectionStringSettings class, because that would recreate the same problem again and in this case you aren't really making an abstraction. Instead, abstract the behavior that uses this configuration value! In the case of the connection string, create an IConnectionFactory or IDbContextFactory abstraction that allows creation of SqlConnection's or DbContext classes. This completely hides the fact that there is a connection string from any consumer, and allows them to call connectionFactory.CreateConnection() instead of having to fiddle around with the connection and the connection string.
My experience is that makes the application code much cleaner, and improves the verifiability of the application.
Thanks every one for responses. I found my solution. The solution is instead of using Default Registry I created another class for resolve the dependencies. Inside the class I used
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
instead of
IContainer Initialize() {
return new Container(c => c.AddRegistry<ControllerRegistry>());
}
Then inside ControllerRegistry I resolved dependencies as follows:
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
Then I called that class inside Global.asax as follows:
Bootstrap.ConfigureDependencies();
Finally inside Global.asax I resolved dependency for Factory class as follows:
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
My entire code is given below:
Bootstrap class (newly created)
public class Bootstrap
{
public static void ConfigureDependencies()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
}
public class ControllerRegistry : Registry
{
public ControllerRegistry()
{
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
}
}
}
Global.asax
Bootstrap.ConfigureDependencies();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());

How to handle authentication in multi-tenant MVC 5 app

I am trying to build a multi-tenant mvc 5 site that uses a single database and differentiates the tenants by schema in Sql Server.
I started with the default Mvc 5 template and updated the ApplicationDBContext that is provided to take a string specifying the schema to use for that tenant like so.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
private string _tenantSchema;
public ApplicationDbContext(string tenantSchema)
: base("Dev", throwIfV1Schema: false)
{
_tenantSchema = tenantSchema;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(_tenantSchema);
base.OnModelCreating(modelBuilder);
}
public static ApplicationDbContext Create(string tenantSchema)
{
return new ApplicationDbContext(tenantSchema);
}
}
And then in the App_Start\IdentityConfig.cs I updated the Create Method of the ApplicationUserClass to use the first part of the Request.Host value to use as the tenantSchema like so
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var tenantSchema = context.Request.Host.Value.Split('.')[0];
var ctx = new ApplicationDbContext(tenantSchema);
var userStore = new UserStore<ApplicationUser>(ctx);
var manager = new ApplicationUserManager(userStore);
so if I were to log into site1.mysite.dev it would authenticate against the tables in the site1 schema is sql server.
When I start the site and access it using the site1 sub domain it correctly uses the site1 Schema to authenticate me. But then if I change url in the browser address bar and log in again it still validates against the site1 schema.
How can I configure the app to use to correct schema to check authentication for each request?
While the code you've shown should sort of work (but it's hard to tell since you left out other key parts, such as Startup.Auth), I would not do it in this way. I would instead change your ApplicationDbContext.Create method to this:
public static ApplicationDbContext Create(
IdentityFactoryOptions<ApplicationDbContext> options, IOwinContext context)
{
var tenantSchema = context.Request.Host.Value.Split('.')[0];
return new ApplicationDbContext(tenantSchema);
}
I would then alter my Startup.Auth as such:
app.CreatePerOwinContext<ApplicationDbContext>(ApplicationDbContext.Create); <---
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
And leave everything else the default. Specifically:
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
....
However, your real problem is most likely that your model builder is cached in the app domain the first time it is created. This is referenced in the documentation here:
http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.onmodelcreating(v=vs.113).aspx
Typically, this method is called only once when the first instance of a derived context is created. The model for that context is then cached and is for all further instances of the context in the app domain. This caching can be disabled by setting the ModelCaching property on the given ModelBuidler, but note that this can seriously degrade performance. More control over caching is provided through use of the DbModelBuilder and DbContextFactory classes directly.
There is actually a nice discussion on this very topic relating to EF and multi-tenant usage (way too long to elaborate here) over at the EF codeplex site:
https://entityframework.codeplex.com/discussions/462765

Accessing Methods/Properties from a class in a separate project without adding reference to the project containing the class (Same solution)

I'm not sure if the title correctly describes my problem. If someone could better describe my problem by reading the following description, please help me by editing the title to something more meaningful.
I'm trying to learn asp.net MVC with Entity Framework and Ninject.
I was having a look at NuGet Gallery application on GitHub and tried to implement a few parts in my project.
I followed the answer provided in this question [How do architect an ASP.Net MVC app with EF?] and designed my project with the following layered structure.
MyDemoApp
MyDemoApp.Domain (Contains POCO Classes)
MyDomain.Service (Contains references to Domain,EF. It contains only Interfaces)
MyDemoApp.Data (Contains references to EF, Domain, Service. It contains classes dealing with Entity Context and Repository)
MyDemoApp.Web (Contains references to ApplicationModel,Data,Domain,Service,Ninject)
MyDemoApp.ApplicationModel (Contains references to Data, Domain, Serivce. It implements the classes from Service project)
MyDemoApp.Web has no business logic and is acting like Humble Object, as mentioned in this answer
I have a Interface IConfiguration in MyDemoApp.Service project which is being implemented by Configuration class located in MyDemoApp.Web where I'm trying to read the connection string. I need to pass this connection string to the object of EntityContext being created in EntityContextFactory located in MydemoApp.Data
If I add a project reference of MyDemoApp.web to MyDemoApp.Data then Visual Studio Prompts me saying that it would cause a circular reference
In the following code return new EntitiesContext(""); How should I pass a parameter over here that would get the connection string that my bindings.cs gets ?
namespace MyDemoApp.Data
{
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContext Create()
{
//TO-DO : Get the Connnectionstring
return new EntitiesContext(""); //Need to pass connection string by calling property from Configuration class in MyDemoApp.Web project
}
}
public class EntitiesContext:DbContext,IEntitiesContext
{
public EntitiesContext(string connectionString) : base(connectionString)
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Provide mapping like foreign key
}
}
}
}
Configuration.cs:
namespace MydemoApp.Web
{
public class Configuration : IConfiguration
{
public string ConnectionString
{
get
{
return ConfigurationManager.ConnectionStrings['dev'].ConnectionString;
}
}
}
}
Bindings.cs:
namespace MydemoApp.Web.Bindings
{
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IConfiguration>().To<Configuration>();
var configuration = new Configuration(); //Gives me Connectionstring
Bind<IEntitiesContext>().ToMethod(context => new EntitiesContext(configuration.ConnectionString)); // This part would help me pass the connection string to the constructor
}
}
}
I don't quite get what problem you are facing. I assume that you need to access a class in Web assembly from Data assembly, but Data assembly already referencing Web assembly.
Can you just inject the configuration interface to your factory constructor, and use that to get the connection string?
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContextFactory(IConfiguration configuration){
this.configuration = configuration;
}
IConfiguration configuration;
public EntitiesContext Create()
{
return new EntitiesContext(configuration.ConnectionString);
}
}
I may misunderstand your question though.
Personally, I think you should leverage the ConfigurationManager in your EntitiesContextFactory.
This would look like:
return new EntitiesContext(System.Configuration.ConfigurationManager.ConnectionStrings["{connectionstringname}"].ConnectionString)
This class is agnostic of whether it is an app.config or web.config that is providing the configuration.
All it stipulates is that application that is hosting the dlls for running, must be configured with an (app/web).config that contains that connection string. your app can test for this at startup since it knows it has a dependency on a database connection for it to work.

Resources