DbProviderFactories.GetFactoryClasses returns no results after installing .NET SQL Client in .NET Core 2.1

Allan Jardine picture Allan Jardine · Aug 24, 2018 · Viewed 11.4k times · Source

I'm porting a library over to .NET Core 2.1 now that it has support for DbProviderFactory. For the most part it has gone fine - it compiles, but when run I get an error:

System.ArgumentException: 'The specified invariant name 'System.Data.SqlClient' wasn't found in the list of registered .NET Data Providers.'

I've used DbProviderFactories.GetFactoryClasses() to check if there are any providers installed, and there doesn't appear to be (0 rows in the resulting table).

So I guess my question is, how can I install the data providers for .NET Core? I've got .NET Framework 4.5 on the machine and it is picking up the data providers without any issue. I don't want to install System.Data.SqlClient as a Nuget for the local project, since that would add a dependency that would make the DbProviderFactory irrelevent. That said, I have attempted to install System.Data.SqlClient in a project that uses my library as a test, and it still isn't picked up.

Answer

Joshua VdM picture Joshua VdM · Aug 27, 2018

In .NET Framework, the providers are automatically available via machine.config and are also registered globally in the GAC. In .NET Core, there is no GAC or global configuration anymore. This means that you'll have to register your provider in your project first, like so:

using System.Collections.Generic;
using System.Data.CData.MySQL; // Add a reference to your provider and use it
using System.Data.Common;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Register the factory
            DbProviderFactories.RegisterFactory("test", MySQLProviderFactory.Instance);

            // Get the provider invariant names
            IEnumerable<string> invariants = DbProviderFactories.GetProviderInvariantNames(); // => 1 result; 'test'

            // Get a factory using that name
            DbProviderFactory factory = DbProviderFactories.GetFactory(invariants.FirstOrDefault());

            // Create a connection and set the connection string
            DbConnection connection = factory.CreateConnection();
            connection.ConnectionString = "Server = test, Database = test";
        }
    }
}

As you can see, I had to add a reference to my Provider, "System.Data.CData.MySQL" in this case.

It's sad that you can't just get all available providers anymore, but this is what we have to work with in .NET core.

(Information from this GitHub corefx issue)