Log4net
  1. Log4net
  2. LOG4NET-88

[PATCH] to AdoNetAppender.cs to support .NET 2.0 connectionStrings configuration section

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.2.10
    • Fix Version/s: 1.2.11
    • Component/s: Appenders
    • Labels:
      None
    • Environment:
      Windows XP .NET 2.0

      Description

      This is a patch for LOG4NET-78 https://issues.apache.org/jira/browse/LOG4NET-78. This adds a new "connectionStringName" attribute (and corresponding ConnectionStringName) property to the AdoNetAppender class. This is a reference to a connection string within the <ConnectionStrings> section of an App.config or Web.config file.

      The choice of name "connectionStringName" is consistent with the naming that Microsoft uses in the various Providers such as SqlMembershipProvider.

      I made sure to put this code in between #if NET_2_0 blocks. However, the patch does not include the required change to the log4net.csproj file which needs to reference the System.Configuration.dll (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.configuration.dll) assembly.

      This is a .NET 2.0 only assembly so I was unsure how to add a conditional compilation element so that the project reference would not break log4net for .NET 1.0 and .NET 1.1.

      If there is a better way to do so, please let me know!

        Activity

        Hide
        Haacked added a comment -

        I applied this against the trunk (version 1.2.10.0) Subversion revision number 429549.

        I didn't notice the option to grant license to ASF but I hereby Grant license to the patch to ASF for inclusion in ASF works.

        Show
        Haacked added a comment - I applied this against the trunk (version 1.2.10.0) Subversion revision number 429549. I didn't notice the option to grant license to ASF but I hereby Grant license to the patch to ASF for inclusion in ASF works.
        Hide
        Ron Grabowski added a comment -

        This looks ok. I'm not really on .NET 2.0 yet (big companies move very very slow). Can one or two other people apply this patch to their build and verify it works correctly.

        As for the project file, I've noticed that most (all?) other .NET open source projects have a project/solution for .NET 2.0 and one for .NET 1.x. I think we need to do that?

        Show
        Ron Grabowski added a comment - This looks ok. I'm not really on .NET 2.0 yet (big companies move very very slow). Can one or two other people apply this patch to their build and verify it works correctly. As for the project file, I've noticed that most (all?) other .NET open source projects have a project/solution for .NET 2.0 and one for .NET 1.x. I think we need to do that?
        Hide
        Nicko Cadell added a comment -

        When you upload an attachment there is a pair of radio buttons just under the file browser. I believe that you are forced to select one of the two options: Grant/Don't Grant.

        We only have a project file for .NET 1.0 because the newer release of VisualStudio can upgrade the project from that format, and this gives us less to maintain. However there are a few manual steps that need to be done after the automatic upgrade: change the pre-processor definitions, change the referenced assemblies. These are documented in http://logging.apache.org/log4net/release/building.html, but that may not be obvious.

        The .NET 2.0 builds already require the System.Configuration.dll.

        The build system uses NAnt to actually do the builds for each platform. The project file is not a critical part of the build process. For this change the build files don't need updating.

        Show
        Nicko Cadell added a comment - When you upload an attachment there is a pair of radio buttons just under the file browser. I believe that you are forced to select one of the two options: Grant/Don't Grant. We only have a project file for .NET 1.0 because the newer release of VisualStudio can upgrade the project from that format, and this gives us less to maintain. However there are a few manual steps that need to be done after the automatic upgrade: change the pre-processor definitions, change the referenced assemblies. These are documented in http://logging.apache.org/log4net/release/building.html , but that may not be obvious. The .NET 2.0 builds already require the System.Configuration.dll. The build system uses NAnt to actually do the builds for each platform. The project file is not a critical part of the build process. For this change the build files don't need updating.
        Hide
        Trevor Williams added a comment -

        Nice patch Phil....I can confirm that the patch works on my asp.net 2.0 / sql server 2005 application under Full Trust.

        Now if I could just get Medium Trust working.....

        Show
        Trevor Williams added a comment - Nice patch Phil....I can confirm that the patch works on my asp.net 2.0 / sql server 2005 application under Full Trust. Now if I could just get Medium Trust working.....
        Hide
        Ron Grabowski added a comment -

        Fixed in r607748.

        I couldn't use Phil's patch because he didn't check the correct radio button that grants us permission to use his code.

        Show
        Ron Grabowski added a comment - Fixed in r607748. I couldn't use Phil's patch because he didn't check the correct radio button that grants us permission to use his code.
        Hide
        Ron Grabowski added a comment -

        Fixed in r607748.

        Show
        Ron Grabowski added a comment - Fixed in r607748.
        Hide
        Bill Sun added a comment -

        How can I get the source code for AdoAppender.cs

        Show
        Bill Sun added a comment - How can I get the source code for AdoAppender.cs
        Hide
        Bill Sun added a comment -
        Show
        Bill Sun added a comment - http://svn.apache.org/viewcvs.cgi//logging/log4net/trunk/src/Appender/AdoNetAppender.cs the link is not working. how can I get this file?
        Hide
        Ron Grabowski added a comment -

        The link works correctly when I click it.

        Its not difficult to support the connectionStringName functionality. Here's basically what's happening:

        // untested
        public class ConnectionStringNameAdoNetAppender : AdoNetAppender
        {
        private string connectionStringName;

        public override void ActivateOptions()
        {
        base.ActivateOptions();
        if (String.IsNullOrEmpty(ConnectionString))

        { ConnectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString; }

        }

        public string ConnectionStringName
        {
        get

        { return connectionStringName; }

        set

        { connectionStringName = value; }

        }
        }

        Show
        Ron Grabowski added a comment - The link works correctly when I click it. Its not difficult to support the connectionStringName functionality. Here's basically what's happening: // untested public class ConnectionStringNameAdoNetAppender : AdoNetAppender { private string connectionStringName; public override void ActivateOptions() { base.ActivateOptions(); if (String.IsNullOrEmpty(ConnectionString)) { ConnectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString; } } public string ConnectionStringName { get { return connectionStringName; } set { connectionStringName = value; } } }
        Hide
        Lewis Moten added a comment -

        Ron, you need to activate the options "after" you set the connection string. Otherwise an error occurs (The ConnectionString property has not been initialized.) Here is a more robust version of the code.

        /// <summary>
        /// An appender for Log4Net that uses a database based on the connection string name.
        /// </summary>
        public class Log4NetConnectionStringNameAdoNetAppender : AdoNetAppender
        {
        private static ILog _Log;

        /// <summary>
        /// Gets the log.
        /// </summary>
        /// <value>The log.</value>
        protected static ILog Log
        {
        get

        { if (_Log == null) _Log = LogManager.GetLogger(typeof(Log4NetConnectionStringNameAdoNetAppender)); return _Log; }

        }

        private string _ConnectionStringName;

        /// <summary>
        /// Initialize the appender based on the options set
        /// </summary>
        /// <remarks>
        /// <para>
        /// This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
        /// activation scheme. The <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> method must
        /// be called on this object after the configuration properties have
        /// been set. Until <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> is called this
        /// object is in an undefined state and must not be used.
        /// </para>
        /// <para>
        /// If any of the configuration properties are modified then
        /// <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> must be called again.
        /// </para>
        /// </remarks>
        public override void ActivateOptions()

        { PopulateConnectionString(); base.ActivateOptions(); }

        /// <summary>
        /// Populates the connection string.
        /// </summary>
        private void PopulateConnectionString()
        {
        // if connection string already defined, do nothing
        if (!String.IsNullOrEmpty(ConnectionString)) return;

        // if connection string name is not available, do nothing
        if (String.IsNullOrEmpty(ConnectionStringName)) return;

        // grab connection string settings
        ConnectionStringSettings settings = ConfigurationManager
        .ConnectionStrings[ConnectionStringName];

        // if connection string name was not found in settings
        if (settings == null)
        {
        // log error
        if (Log.IsErrorEnabled)
        Log.ErrorFormat("Connection String Name not found in Configuration:

        {0}

        ",
        ConnectionStringName);
        // do nothing more
        return;
        }

        // retrieve connection string from the name
        ConnectionString = settings.ConnectionString;
        }

        /// <summary>
        /// Gets or sets the name of the connection string.
        /// </summary>
        /// <value>The name of the connection string.</value>
        public string ConnectionStringName
        {
        get

        { return _ConnectionStringName; }

        set

        { _ConnectionStringName = value; }

        }
        }

        Show
        Lewis Moten added a comment - Ron, you need to activate the options "after" you set the connection string. Otherwise an error occurs (The ConnectionString property has not been initialized.) Here is a more robust version of the code. /// <summary> /// An appender for Log4Net that uses a database based on the connection string name. /// </summary> public class Log4NetConnectionStringNameAdoNetAppender : AdoNetAppender { private static ILog _Log; /// <summary> /// Gets the log. /// </summary> /// <value>The log.</value> protected static ILog Log { get { if (_Log == null) _Log = LogManager.GetLogger(typeof(Log4NetConnectionStringNameAdoNetAppender)); return _Log; } } private string _ConnectionStringName; /// <summary> /// Initialize the appender based on the options set /// </summary> /// <remarks> /// <para> /// This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object /// activation scheme. The <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> method must /// be called on this object after the configuration properties have /// been set. Until <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> is called this /// object is in an undefined state and must not be used. /// </para> /// <para> /// If any of the configuration properties are modified then /// <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> must be called again. /// </para> /// </remarks> public override void ActivateOptions() { PopulateConnectionString(); base.ActivateOptions(); } /// <summary> /// Populates the connection string. /// </summary> private void PopulateConnectionString() { // if connection string already defined, do nothing if (!String.IsNullOrEmpty(ConnectionString)) return; // if connection string name is not available, do nothing if (String.IsNullOrEmpty(ConnectionStringName)) return; // grab connection string settings ConnectionStringSettings settings = ConfigurationManager .ConnectionStrings [ConnectionStringName] ; // if connection string name was not found in settings if (settings == null) { // log error if (Log.IsErrorEnabled) Log.ErrorFormat("Connection String Name not found in Configuration: {0} ", ConnectionStringName); // do nothing more return; } // retrieve connection string from the name ConnectionString = settings.ConnectionString; } /// <summary> /// Gets or sets the name of the connection string. /// </summary> /// <value>The name of the connection string.</value> public string ConnectionStringName { get { return _ConnectionStringName; } set { _ConnectionStringName = value; } } }
        Hide
        Christof Nordiek added a comment -

        This hack seems only to get the connectionString attribute from the connectionString section. It should only get the providerName from there.

        Show
        Christof Nordiek added a comment - This hack seems only to get the connectionString attribute from the connectionString section. It should only get the providerName from there.

          People

          • Assignee:
            Ron Grabowski
            Reporter:
            Haacked
          • Votes:
            0 Vote for this issue
            Watchers:
            11 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development