Search code examples
c#ado.netapp-configsqlconnectionconfigurationmanager

Why is sqlconnection.open nosing around in my config file?


Today I thought, Oh, I'll just add some SQL logging to a C# SFTP custom (console) program we have. I didn't write it, and it has perhaps an odd configuration file. It looks like the SQL Performance Counters require a well conformed config file? Add the catch for TypeInitializationException gave some more specific and useful info.

So I am getting the connection string from the app.config file, but to show why I'm frustrated, I hard-coded the connection string below. If I'm providing a full connection string, why would it go to the config file. Apparently SqlPerformanceCounters is picky about these things???

            if (!String.IsNullOrWhiteSpace(SqlConnectionString))
            {
                try
                {
                    WriteLogConsole("SqlConnectionObj - about to open with SqlConnectionString='" + 
                                     SqlConnectionString + "'");

                    //SqlConnection SqlConnectionObj = new SqlConnection(SqlConnectionString); 
                    // Even using a hard-coded connection string I have this issue! 
                    SqlConnection SqlConnectionObj = new SqlConnection("Server=abc;Database=MyDBName;Trusted_Connection=true"); 
                    SqlConnectionObj.Open(); 
                    WriteLogConsole("SqlConnectionObj - opened successfully");
                }
                catch (TypeInitializationException ex)
                {
                    WriteLogConsole("TypeInitializationException=" + ex.ToString());
                    // don't stop, keep going.  Logging is nice, but not critical 
                }
                catch (SqlException ex)
                {
                    WriteLogConsole("SqlException=" + ex.ToString());
                    // don't stop, keep going.  Logging is nice, but not critical 
                }
                catch (Exception ex)
                {
                    WriteLogConsole("System.Exception=" + ex.Message);
                    // don't stop, keep going.  Logging is nice, but not critical 
                }

            }

The short version of the error thrown is this:

Unrecognized configuration section CustomAppSettings/LogExceptionsToFile

Full exception:

    SqlConnectionObj - about to open with SqlConnectionString='Server=abc;Database=MyDBName;Trusted_Connection=true'
    Exception thrown: 'System.TypeInitializationException' in System.Data.dll
    TypeInitializationException=System.TypeInitializationException: The type initializer for 'System.Data.SqlClient.SqlConnection' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Data.SqlClient.SqlConnectionFactory' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Data.SqlClient.SqlPerformanceCounters' threw an exception. ---> System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize ---> System.Configuration.ConfigurationErrorsException: Unrecognized configuration section CustomAppSettings/LogExceptionsToFile
     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.ConfigurationManager.PrepareConfigSystem()
   at System.Configuration.ConfigurationManager.GetSection(String sectionName)
   at System.Configuration.PrivilegedConfigurationManager.GetSection(String sectionName)
   at System.Diagnostics.DiagnosticsConfiguration.GetConfigSection()
   at System.Diagnostics.DiagnosticsConfiguration.Initialize()
   at System.Diagnostics.DiagnosticsConfiguration.get_SwitchSettings()
   at System.Diagnostics.Switch.InitializeConfigSettings()
   at System.Diagnostics.Switch.InitializeWithStatus()
   at System.Diagnostics.Switch.get_SwitchSetting()
   at System.Data.ProviderBase.DbConnectionPoolCounters..ctor(String categoryName, String categoryHelp)
   at System.Data.SqlClient.SqlPerformanceCounters..ctor()
   at System.Data.SqlClient.SqlPerformanceCounters..cctor()
   --- End of inner exception stack trace ---
   at System.Data.SqlClient.SqlConnectionFactory..cctor()
   --- End of inner exception stack trace ---
   at System.Data.SqlClient.SqlConnection..cctor()
   --- End of inner exception stack trace ---
   at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
   at WinSCPWrapperGet.Program.Main(String[] args)

I think it's related to something like this.

What do I have to change to make it happy? I saw other posts about using but I don't have a group. I added everything below in as an attempt to fix the issue. The rest of the program runs fine and uses the config file as desired.

<configuration>
  <configSections> <!-- this was not here when I first got the error, 
         me thinks I need something like to fix this issue -->
    <sectionGroup name="CustomAppSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="MyApp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
    </sectionGroup>
  </configSections>  
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
  </startup>
  <CustomAppSettings>
      <!-- we have many more parms, but here is an example; 
           each SFTP site can have about 10 config parms --> 
      <Site1>
         <add key="HostName" value="sftp.somesite1.com"/>
         <add key="HostPort" value=""/>
      </Site1>
      <Site2>
         <add key="HostName" value="sftp.somesite1.com"/>
         <add key="HostPort" value=""/>
      </Site2>
    ... etc...

NOTE: This is in production now, and I am enhancing it. We have maybe a few dozen config files in different scheduled tasks, so I would hate to change all of them, even if they are not designed perfectly.

Found this: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/performance-counters

It tells us that we can tune the performance counters in the config file:

<system.diagnostics>
  <switches>
    <add name="ConnectionPoolPerformanceCounterDetail"
         value="4"/>
  </switches>
</system.diagnostics>

So bottom line, I just need to know how to make my config file work with SQL, even though the connection string in the config is not the issue.


Solution

  • The group is not needed, so far the following has got around the original issue:

    <configuration>
      <configSections>
          <section name="CustomAppSettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
      </configSections>  
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
      </startup>
      <CustomAppSettings>
          etc... 
    

    Reference: https://blog.ivankahl.com/creating-custom-configuration-sections-in-app-config/