The 'DbProviderFactories' section can only

2020-08-23 09:27发布

问题:

We are receiving this error when calling a WCF .net 4.0 service using entity framework.

The 'DbProviderFactories' section can only appear once per config file

It is the first app on the server using EF and other .net 4.0 WCF services are not receiving this error.

Is there any way to correct this error with out editing the machine config file on the server?

回答1:

Maybe you could create web.config entries which override any machine-wide settings you want changed.

Described here:

Override machine.config by web.config

Putting the <clear /> instruction inside of the DbProviderFactories tags in the web config to clear out and then override the duplicate entries made in the machine config. Thus doing a hack-work around of the error in the machine.config.



回答2:

The installation for IBM DB2 .NET provider, causes an empty DbProviderFactories, see below. Just delete the second empty entry DbProviderFactories

<system.data>
    <DbProviderFactories>
        <add name="IBM DB2 for i .NET Provider" invariant="IBM.Data.DB2.iSeries" description=".NET Framework Data Provider for IBM i" type="IBM.Data.DB2.iSeries.iDB2Factory, IBM.Data.DB2.iSeries, Version=12.0.0.0, Culture=neutral, PublicKeyToken=9cdb2ebfb1f93a26" />
    </DbProviderFactories>
    <DbProviderFactories />
</system.data>


回答3:

You have to update Machine.config file located in the below paths.

  • C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config
  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Machine.Config

For 64-bit machines, Machine.config will be located in ...\Framework64\...

The block to pay attention to is this:

<system.data>
    <DbProviderFactories>
        <add name="IBM DB2 for i5/OS .NET Provider" invariant="IBM.Data.DB2.iSeries" description=".NET Framework Data Provider for i5/OS" type="IBM.Data.DB2.iSeries.iDB2Factory, IBM.Data.DB2.iSeries, Version=12.0.0.0, Culture=neutral, PublicKeyToken=9cdb2ebfb1f93a26"/>
        <add name="Microsoft SQL Server Compact Data Provider" invariant="System.Data.SqlServerCe.3.5" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=3.5.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
        </DbProviderFactories>
<!-- This is the line to remove - empty element --><DbProviderFactories/>
</system.data>


回答4:

As @yonsk already mentioned why this problem occurs (duplicate entry of ), you can create a console application which can fix the machine.config file and then, invoke that console application from your Application's Installer or from your Application whenever you get the Exception. The following code can be used for the console application that will fix the machine.config file.

class Program
    {
        static void Main()
        {
            string machineConfigFilePath = RuntimeEnvironment.SystemConfigurationFile;

            XDocument xdoc = XDocument.Load(machineConfigFilePath);

            XElement[] elements = xdoc.XPathSelectElements("//configuration/system.data/DbProviderFactories").ToArray();

            if (elements.Any())
            {
                foreach (XElement anElement in elements)
                {
                    if (!anElement.HasElements)
                        anElement.Remove();
                }
            }

            xdoc.Save(machineConfigFilePath);
        }
    }

If you want to call the console application, from your Application, you would need to invoke that as Administrator. So, the following snippet may help to invoke that console application as Administrator (The user will be prompted with a dialog to accept..)

 try
            {
                Process process = Process.Start(new ProcessStartInfo
                {
                    Verb = "runas",
                    FileName = "/Path/to/the/console/application",
                    UseShellExecute = true,
                    CreateNoWindow = true,

                });
                process.WaitForExit();
                int exitCode = process.ExitCode;
            }
            catch (Exception ex)
            {

            }