Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app.config breaks the library #287

Closed
yorek opened this issue Oct 25, 2019 · 11 comments
Closed

app.config breaks the library #287

yorek opened this issue Oct 25, 2019 · 11 comments
Assignees
Milestone

Comments

@yorek
Copy link

yorek commented Oct 25, 2019

Describe the bug

If you have an app.config file in your solution it will cause the error "The type initializer for 'Microsoft.Data.SqlClient.SqlConnection' threw an exception"

An exception of type 'System.TypeInitializationException' occurred in Microsoft.Data.SqlClient.dll but was not handled in user code: 'The type initializer for 'Microsoft.Data.SqlClient.SqlConnection' threw an exception.'
 Inner exceptions found, see $exception in variables window for more details.
 Innermost exception 	 System.Xml.XmlException : Data at the root level is invalid. Line 1, position 1.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
   at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Configuration.XmlUtil..ctor(Stream stream, String name, Boolean readToFirstElement, ConfigurationSchemaErrors schemaErrors)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()

To reproduce

Just create a sample console app that uses Microsoft.Data.SqlClient and add an app.config file. It could be even an empty file.

Expected behavior

Do not crash :)

Further technical details

Microsoft.Data.SqlClient version: 1.0.19269.1
.NET target: (e.g. Framework Core 2.1)
Operating system: (e.g. Windows 10)

@yukiwongky
Copy link
Contributor

@yorek From the error you're getting (Data at the root level is invalid. Line 1, position 1.), looks like your app.config file is invalid. If I use an app config autogenerated by visual studio

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

I was able to initialize SqlConnection just fine.

@saurabh500
Copy link
Contributor

@yukiwongky What is the behavior on .Net framework v4.8 ?

I know that SqlConnection class tries to load some values from the App.Config to initialize providers for always encrypted and for auth providers for AAD.

It might be worth checking out the behavior of DbProviderFactory (an API which I picked up, which depends on App.config) to see what the behavior is, in case of a malformed app.config

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/obtaining-a-dbproviderfactory

If the API fails to load the db provider factory silently, then it may perhaps be good to make SqlConnection static constructor to fail silently instead of preventing initialization.

@yorek
Copy link
Author

yorek commented Oct 25, 2019

@yukiwongky right but if the file is there and is empty, or contains json, you'll get the error. If "app.config" file must be an XML, it's better to call it out clearly in the doc, as with System.Data.SqlClient, there are no problem instead.

@yukiwongky
Copy link
Contributor

@saurabh500 I see the exception comes from SqlConnection.cs#L40 when the configuration file can not be loaded. And I also found in DbProviderFactories.cs that the exception is just ignored. We can do the same in the MDS driver as well, instead of throwing an exception, make sqlColumnEncryptionEnclaveProviderConfigurationSection null if the configuration file is not found.

@saurabh500
Copy link
Contributor

Yeah I agree with the approach

@yukiwongky
Copy link
Contributor

@yorek we're working towards removing the need for app.config as mentioned in #158. Please stay tune.

@yorek
Copy link
Author

yorek commented Oct 29, 2019

@yukiwongky great! :)

@yukiwongky
Copy link
Contributor

Hi @yorek, we have the fix in v1.1.0-preview2. Can you give it a try?

@yorek
Copy link
Author

yorek commented Nov 10, 2019

Hi. Just tried it. Now I receive just this error:

Unhandled exception. System.TypeInitializationException: The type initializer for 'Microsoft.Data.SqlClient.SqlAuthenticationProviderManager' threw an exception.
 ---> System.InvalidOperationException: Failed to read the config section for authentication providers.
 ---> System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
 ---> System.Configuration.ConfigurationErrorsException: Data at the root level is invalid. Line 1, position 1. (C:\Work\_lab\azure-sql-connection\bin\Debug\netcoreapp3.0\azure-sql-connection.dll.config line 1)
 ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
   at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Configuration.XmlUtil..ctor(Stream stream, String name, Boolean readToFirstElement, ConfigurationSchemaErrors schemaErrors)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
   --- End of inner exception stack trace ---
   at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
   at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
   at System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()
   at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
   --- End of inner exception stack trace ---
   at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
   at System.Configuration.ClientConfigurationSystem.PrepareClientConfigSystem(String sectionName)
   at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
   at System.Configuration.ConfigurationManager.GetSection(String sectionName)
   at Microsoft.Data.SqlClient.SqlAuthenticationProviderManager..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.Data.SqlClient.SqlAuthenticationProviderManager..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool, SqlAuthenticationProviderManager sqlAuthProviderManager)
   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)     
   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at Microsoft.Data.SqlClient.SqlConnection.Open()
   at Azure.SQLDB.Samples.Connection.Program.Main(String[] args) in C:\Work\_lab\azure-sql-connection\Program.cs:line 12

I'm using this simple code to test the library:

using Microsoft.Data.SqlClient;

namespace Azure.SQLDB.Samples.Connection
{
    class Program
    {
        static void Main(string[] args)
        {
            // Connection string can be found in the portal
            using(var conn = new SqlConnection("Server=localhost; Integrated Security=SSPI;"))
            {
                conn.Open();
                var cmd = new SqlCommand("SELECT Column1 FROM dbo.Table1", conn);
                var result = cmd.ExecuteScalar();
                conn.Close();
            }           
        }
    }
}

and this is the .csprj file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <RootNamespace>Azure.SQLDB.Samples.Connection</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Data.SqlClient" Version="1.1.0-preview2.19309.1" />
  </ItemGroup>
</Project>

It works nice until you create an app.config file in the same folder. The app.config file is set to be

{}

David-Engel added a commit to David-Engel/SqlClient that referenced this issue Nov 19, 2019
Don't throw exception on invalid app.config files (dotnet#287)
David-Engel added a commit that referenced this issue Nov 20, 2019
Don't throw exception on invalid app.config files (#287)
@cheenamalhotra
Copy link
Member

Addressed in #319

@johnsimons
Copy link

I don't think this is fixed in v1.1.0

I'm still getting the following exception when my config looks something like:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="Logging.Level" value="Debug" />
  </appSettings>
  <system.diagnostics>
    <sources>
      <source name="Halibut">
        <listeners>
          <add name="nlog" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="Halibut" value="Verbose" />
    </switches>
    <sharedListeners>
      <add name="nlog" type="NLog.NLogTraceListener, NLog" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
  <runtime>
    <gcServer enabled="true" />
  </runtime>
</configuration>

Exception stacktrace:

--Inner Exception--
The type initializer for 'Microsoft.Data.SqlClient.SqlAuthenticationProviderManager' threw an exception.
System.TypeInitializationException
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at Microsoft.Data.SqlClient.SqlConnection.Open()
  ....

--Inner Exception--
Failed to read the config section for authentication providers.
System.InvalidOperationException
   at Microsoft.Data.SqlClient.SqlAuthenticationProviderManager..cctor()

--Inner Exception--
Configuration system failed to initialize
System.Configuration.ConfigurationErrorsException
   at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
   at System.Configuration.ClientConfigurationSystem.PrepareClientConfigSystem(String sectionName)
   at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
   at System.Configuration.ConfigurationManager.GetSection(String sectionName)
   at Microsoft.Data.SqlClient.SqlAuthenticationProviderManager..cctor()

--Inner Exception--
Unrecognized configuration section system.diagnostics. (C:\buildAgent\work\abb2fbfce959a439\tests\Octopus.E2ETests.API.dll.config line 6)
System.Configuration.ConfigurationErrorsException
   at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
   at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
   at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants