3

I currently have 2 projects in my solution, an ASP.NET Core Web Application and a .NET 4.6.1 (non-core) class library. In my class library, I have added Entity Framework 6 and, using Database First generation, created all my db context classes. Inside the class library, everything is working as expected; however, when I try to access the ef classes from the .NET Core Web App, it doesn't have a connection string to use and fails.

Now, in the old ways, I know that I could copy the connection string settings from the app.config in my class library to the web.config in the web application, but .NET Core doesn't support this.

I've tried using the steps outlined here, but that only works for Code-First db generation (which I am not doing). I also looked into switching to using EntityFrameworkCore, but I can't get the db-first generation to happen (using this overview).

Is there any way to achieve what I am trying to do?

Nick DeMayo
  • 1,086
  • 2
  • 15
  • 23

2 Answers2

3

Below is how you can provide the entire configuration in the codebase for EF models and how to provide the connection strings at runtime. I recently struggled with this too because documentation on this is a little hard to find.

Let's assume you generated your model from your database (DB-First): MyEntities.edmx

You will have a partial class in your project such as this:

public partial class MyEntities : DbContext
{
    public MyEntities ()
        : base("name=MyEntities")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<MyTable> MyTable { get; set; }
}

When you generated your model in VS, if you selected to store the connection string in the config file the automatic code generation will put the connection string config name in the constructor as it is above: public MyEntities(): base("name=MyEntities")

And in the config of your project you will have something like:

<configuration> <connectionStrings> <add name="MyEntities" connectionString="metadata=res://MyProject/MyEntities.csdl|res://MyProject/MyEntities.ssdl|res://MyProject/MyExchangeEntities.msl;provider=System.Data.SqlClient;provider connection string='data source=SERVERADDRESS;initial catalog=DATABASENAME;persist security info=True;user id=USERID;password=PASSWORD;MultipleActiveResultSets=True;App=EntityFramework'" /> </connectionStrings> </configuration>

Now to bypass this, if you take a look at the DbContext constructor: public DbContext(string nameOrConnectionString); it actually says you can pass the connection string directly to it.

So all that you need to do is to extend this partial class and add another constructor that takes a connectionstring.

public partial class MyEntities
{
    /// <summary>
    /// This constructor allows us to pass connection strings at runtime
    /// </summary>
    /// <param name="connectionString">Entity Framework connection string</param>
    public MyEntities(string connectionString) : base(connectionString)
    {

    }
}

Even though it is obvious, I just want to mention that we extend the partial class instead of modifying the auto generated one so it doesn't get overwritten when we re-generate the model in the future.

To connect using your connection string you simply construct your object like this: new MyEntities("metadata=res://MyProject/MyEntities.csdl|res://MyProject/MyEntities.ssdl|res://MyProject/MyExchangeEntities.msl;provider=System.Data.SqlClient;provider connection string='data source=SERVERADDRESS;initial catalog=DATABASENAME;persist security info=True;user id=USERID;password=PASSWORD;MultipleActiveResultSets=True;App=EntityFramework'");

And finally, if you want to provide the EF configuration in the codebase as well, it can be done like this:

/// DbConfiguration belongs to System.Data
public class EntityFrameworkConfig : DbConfiguration
{
    public EntityFrameworkConfig()
    {
        //We set configurations for entity framework here so that we don't have to add it in the app.config
        this.SetDefaultConnectionFactory(new SqlConnectionFactory());
        this.SetProviderServices(SqlProviderServices.ProviderInvariantName, SqlProviderServices.Instance);
    }
}

/// <summary>
/// This class with the DbConfigurationType attribute allows EntityFramework to know    
/// to get its config from the EntityFrameworkConfig class instead of the app.config
/// </summary>
[DbConfigurationType(typeof(EntityFrameworkConfig))]
public partial class MyEntities
{
    /// <summary>
    /// This constructor allows us to pass connection strings at runtime
    /// </summary>
    /// <param name="connectionString">Entity Framework connection string</param>
    public MyEntities(string connectionString) : base(connectionString)
    {

    }
}
Sal
  • 5,129
  • 5
  • 27
  • 53
  • I like this, because it looks very straightforward... will give it a shot today. One question though... is there any way to put the connection string in the appsettings.json file so that I don't have to recompile to change the connection string? – Nick DeMayo Jun 20 '16 at 12:15
  • Ok, I got it all wired up, and it looked pretty promising, but I still get this error: Additional information: The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. – Nick DeMayo Jun 20 '16 at 12:37
  • Did you try removing the metadata part from your connection string? http://stackoverflow.com/questions/7944596/entity-framework-cant-use-the-dbcontext-model-being-created – Sal Jun 21 '16 at 13:05
  • I did, yeah, and that's when I received the error message. – Nick DeMayo Jun 21 '16 at 14:31
  • EntityFramework actually requires a different kind of connection string. I'm correcting it in my answer above. The new connection string example contains the locations of the csdl and ssdl files which is required for it to work. – Sal Jul 31 '16 at 00:27
  • Unfortunately, my connection string already contained those references. I appreciate the continued support, but I've move on from .NET Core for now, with plans to refactor in the future. – Nick DeMayo Aug 01 '16 at 11:58
  • I have found that it doesn't like the generated connection string because it contains the string `"` in it. If you replace those (`provider connection string="..."`) with `'`, it will work as expected. – SaoBiz Feb 19 '17 at 22:48
1

Long story short: You have to copy your ConnectionString to the web.config/app.config of your hosting project. Your Class Library cant run with out Console Application / MVC / Web API, without one of this applications its just a dll. So to sum it up, you need to copy all Connection Strings and other important to the web.config file of the hosting project.

Ron
  • 1,744
  • 6
  • 27
  • 53