dotnet / ef6

This is the codebase for Entity Framework 6 (previously maintained at https://entityframework.codeplex.com). Entity Framework Core is maintained at https://github.com/dotnet/efcore.
https://docs.microsoft.com/ef/ef6
MIT License
1.41k stars 538 forks source link

EF6.5 + Azure + ASP.NET MVC + Microsoft.Data.SqlClient ProviderName #2250

Closed 3nth closed 1 month ago

3nth commented 1 month ago

Locally our MVC NET Framework app is able to use Microsoft.Data.SqlClient just fine having made all the relevent changes, and with the connection string in Web.Config setting the ProviderName="Microsoft.Data.SqlClient" appropriately.

However, in Azure Web Services, the connection strings don't have ProviderName and I cannot figure out how to get the app to use Microsoft.Data.SqlClient instead of System.Data.SqlClient.

ErikEJ commented 1 month ago

yeah, sadly Azure App Service configuration system is hard coded to "System.Data.SqlClient" as you discovered.

But I think there is a workaround as described here: https://github.com/ErikEJ/EntityFramework6PowerTools/issues/129#issuecomment-1576540580

@3nth

3nth commented 1 month ago

Heh, didn't think to tell it a little lie: "I got your System.Data.SqlClient right here"

We are using this in a common library, which is also used by other apps which are upgraded to .NET Core with no issue:

    public class EbisuConfiguration : MicrosoftSqlDbConfiguration
    {
        public EbisuConfiguration()
        {
            SetProviderFactory(MicrosoftSqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance);
            SetProviderServices(MicrosoftSqlProviderServices.ProviderInvariantName, MicrosoftSqlProviderServices.Instance);
            SetExecutionStrategy(MicrosoftSqlProviderServices.ProviderInvariantName, () => new MicrosoftSqlAzureExecutionStrategy());
        }
    }

    [DbConfigurationType(typeof(EbisuConfiguration))]
    public class EbisuContext : DbContext
    {}

and was trying this in Application_Start to no avail

DbConfiguration.SetConfiguration(new EbisuConfiguration());

Will try having this NET Framework web app use it's own.

Is the fact that configuration referenced by the DbContext via DbConfigurationType attribute is different going to be an issue?

Maybe this is possible? (Not sure how important it was for the Configuration to be in the same assembly)

    public class EbisuConfiguration : MicrosoftSqlDbConfiguration
    {
        public EbisuConfiguration()
        {
            SetProviderFactory(MicrosoftSqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance);
            SetProviderServices(MicrosoftSqlProviderServices.ProviderInvariantName, MicrosoftSqlProviderServices.Instance);
            SetExecutionStrategy(MicrosoftSqlProviderServices.ProviderInvariantName, () => new MicrosoftSqlAzureExecutionStrategy());

            // tell me lies, tell me sweet little lies
            SetProviderFactory("System.Data.SqlClient", Microsoft.Data.SqlClient.SqlClientFactory.Instance);
            SetProviderServices("System.Data.SqlClient", MicrosoftSqlProviderServices.Instance);
            SetExecutionStrategy("System.Data.SqlClient", () => new MicrosoftSqlAzureExecutionStrategy());
        }
    }
3nth commented 1 month ago

To answer my own question, this appears to work just fine.

Locally, you can test the "Azure Connection Strings Experience" by setting ProviderName="System.Data.SqlClient" on the connection strings, and will get Microsoft.Data.SqlClient at runtime with this (same assembly as Global.asax.cs not required)

    public class EbisuConfiguration : MicrosoftSqlDbConfiguration
    {
        public EbisuConfiguration()
        {
            // Map "Microsoft.Data.SqlClient" -> Microsoft.Data.SqlClient Provider
            SetProviderFactory(MicrosoftSqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance);
            SetProviderServices(MicrosoftSqlProviderServices.ProviderInvariantName, MicrosoftSqlProviderServices.Instance);
            SetExecutionStrategy(MicrosoftSqlProviderServices.ProviderInvariantName, () => new MicrosoftSqlAzureExecutionStrategy());

            // Map "System.Data.SqlClient" -> Microsoft.Data.SqlClient Provider
            SetProviderFactory(SqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance);
            SetProviderServices(SqlProviderServices.ProviderInvariantName, MicrosoftSqlProviderServices.Instance);
            SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new MicrosoftSqlAzureExecutionStrategy());
        }
ErikEJ commented 1 month ago

My eyes hurt, but if that works for you. Wonder if order matters?

3nth commented 1 month ago

I'm thinking order does matter for the .NET Core apps which I believe come in with no ProviderName set in the connection string, but since these now map to the same providers it doesn't actually matter?

Also, since we've done this on our DbContext:

    [DbConfigurationType(typeof(EbisuConfiguration))]
    public class EbisuContext : DbContext

We don't actually need to do this in the Global.asax.cs Application_Start

DbConfiguration.SetConfiguration(new EbisuConfiguration());
ErikEJ commented 1 month ago

@AndriySvyryd Feel free to close this!