Singleton, Регистрируясь и Глобальные Настройки - Хорошая или Плохая реализация?

Обычно поток подобен Controller -> Service -> Dao. Таким образом, вы можете создать Сервис, который будет вызывать соответствующий дао / репозиторий. Также, пожалуйста, проверьте эту ссылку.

8
задан dr. evil 28 April 2009 в 07:36
поделиться

8 ответов

First - could you write the log writer as a trace listener, and use Trace.Write etc from the methods?

Do you actually need an instance here? That would be useful, for example, if you wanted to abstract it as a TextWriter or similar - but if it is going to be a standalone singleton, can the methods not use static methods directly, i.e. Log.Write(...) (rather than passing in a log instance)?

Re the general problem - it depends on the types that are doing the logging. For "manager" (etc) classes, you might consider using dependency injection (Unity, StructureMap, etc) to automate this. I wouldn't normally use injection with DTOs, though.

4
ответ дан 5 December 2019 в 17:41
поделиться

Even if you don't want suggestions of "use Log4X" (although you don't say exactly why you want to reinvent the wheel) it would seem sensible to look at the design decisions made by various logging libraries.

In my experience the problems of tight coupling aren't as relevant when applied to logging - in particular, I rarely want to test the logging side of my app, and I don't mind if it logs to the console during unit testing.

In short, the "normal" pattern of:

private static readonly Logger log = LogManager.GetLogger(...);

(with appropriate name changes etc) is aesthetically unappealing in its use of static methods, but works pretty well in practice. At least, that's been my experience.

3
ответ дан 5 December 2019 в 17:41
поделиться

You can probably use a singleton here. You'll have a tight coupling between every class in the application and the logger class but if the logger class and the global settings class really are needed in every class this can be acceptable.

2
ответ дан 5 December 2019 в 17:41
поделиться

Я лично использую статический класс в таком случае. Класс имеет статические поля конфигурации (для ручного эксперимента), а также некоторые функции для их заполнения с использованием конфигурации из соответствующего раздела файла .config.

По сути, это очень похоже на то, что вы имели бы с DI, поскольку вы можете «ввести» новый конфиг. Чтобы изменить конфигурацию на новую модель, я просто изменяю поле файла .config, в котором содержится «активная» секция конфигурации.

Это просто в использовании, легко поддерживать, и все это понимают ... Я не вижу какой-то конкретный недостаток ...

1
ответ дан 5 December 2019 в 17:41
поделиться

Logging and settings are actually handled in two different ways, so if I understood correctly, your actual question was more related to handling global settings between assemblies.

Regarding logging, things are pretty clear - using a global Singleton for that is common, although it does tightly couple your libraries to the log library. Using Trace listeners is an even better solution IMHO.

But when talking about application settings, you should certainly avoid making them global. Keep all application related settings located at one place only (those that should be persisted), but not statically available to other libraries. Therefore, passing appropriate settings to other assemblies will have to be the caller's responsibility, not vice versa.

0
ответ дан 5 December 2019 в 17:41
поделиться

Is this ASP.Net? If so, you can use The Error Event in the Global.asax.

For your many dependencies, have you considered using a dependency injection framework?

Update

I'm not sure the performance implication nor how relevant performance is to your app, but this framework looks interesting: PostSharp, A blog post about it.

You also might be able to leverage the Conditional attribute.

If you use PostSharp, I would be interested how it works out.

0
ответ дан 5 December 2019 в 17:41
поделиться

Одна вещь, которую вы можете исследовать, - это пакетная функция. Утверждается, что следование этой методике устраняет некоторые проблемы, которые приводят к высокой связи между классами. Точнее говоря, это будет означать, что в каждой функции в вашем приложении будет только один класс, отвечающий за общение с поставщиком конфигурации (который вполне может быть частью самой функции конфигурации / настройки / установки). Уровень связи все еще находится на стороне высокого уровня, но поскольку он четко определен, он должен быть управляемым.

0
ответ дан 5 December 2019 в 17:41
поделиться

Нечто похожее:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Config;
using log4net.Appender;
using System.Reflection;
using System.IO;
using System.Globalization;
using log4net.Core;
using System.Web;

namespace GenApp.Utils
{
  ///<summary> Wrapper around log4net with dynamically adjustable verbosity</summary>
  public class Logger
  {

    private static Logger inst = new Logger ();
    public static Logger Inst ()
    {
      inst.ConfigureLogging ();
      return inst;
    }


    public enum DebugLevel : int
    {
      Fatal_Msgs = 0,
      Fatal_Error_Msgs = 1,
      Fatal_Error_Warn_Msgs = 2,
      Fatal_Error_Warn_Info_Msgs = 3,
      Fatal_Error_Warn_Info_Debug_Msgs = 4
    }

    public static void Debug ( GenApp.Bo.User objUser, ILog logger, string msg )
    {
      DebugLevel debugLevel = (DebugLevel)objUser.UserSettings.LogLevel;
      string strLogLevel = Logger.GetLogTypeString ( debugLevel );
      inst.SetLogingLevel ( strLogLevel );
      logger.Debug ( msg );

    } //eof method 


    public static void Info ( GenApp.Bo.User objUser, ILog logger, string msg )
    {
      DebugLevel debugLevel = (DebugLevel)objUser.UserSettings.LogLevel;
      string strLogLevel = Logger.GetLogTypeString ( debugLevel );
      inst.SetLogingLevel ( strLogLevel );
      logger.Info ( msg );

    } //eof method 


    public static void Warn ( GenApp.Bo.User objUser, ILog logger, string msg )
    {
      DebugLevel debugLevel = (DebugLevel)objUser.UserSettings.LogLevel;
      string strLogLevel = Logger.GetLogTypeString ( debugLevel );
      inst.SetLogingLevel ( strLogLevel );
      logger.Warn ( msg );

    } //eof method 


    public static void Error ( GenApp.Bo.User objUser, ILog logger, string msg )
    {
      DebugLevel debugLevel = (DebugLevel)objUser.UserSettings.LogLevel;
      string strLogLevel = Logger.GetLogTypeString ( debugLevel );
      inst.SetLogingLevel ( strLogLevel );
      logger.Error ( msg );
    } //eof method 


    public static void Fatal ( GenApp.Bo.User objUser, ILog logger, string msg )
    {
      DebugLevel debugLevel = (DebugLevel)objUser.UserSettings.LogLevel;
      string strLogLevel = Logger.GetLogTypeString ( debugLevel );
      inst.SetLogingLevel ( strLogLevel );
      logger.Fatal ( msg );
    } //eof method 


    /// <summary>
    /// Activates debug level 
    /// </summary>
    /// <sourceurl>http://geekswithblogs.net/rakker/archive/2007/08/22/114900.aspx</sourceurl>
    private void SetLogingLevel ( string strLogLevel )
    {

      this.ConfigureLogging ();
      string strChecker = "WARN_INFO_DEBUG_ERROR_FATAL";

      if (String.IsNullOrEmpty ( strLogLevel ) == true || strChecker.Contains ( strLogLevel ) == false)
        throw new ArgumentOutOfRangeException ( " The strLogLevel should be set to WARN , INFO , DEBUG ," );



      log4net.Repository.ILoggerRepository[] repositories = log4net.LogManager.GetAllRepositories ();

      //Configure all loggers to be at the debug level.
      foreach (log4net.Repository.ILoggerRepository repository in repositories)
      {
        repository.Threshold = repository.LevelMap[strLogLevel];
        log4net.Repository.Hierarchy.Hierarchy hier = (log4net.Repository.Hierarchy.Hierarchy)repository;
        log4net.Core.ILogger[] loggers = hier.GetCurrentLoggers ();
        foreach (log4net.Core.ILogger logger in loggers)
        {
          ( (log4net.Repository.Hierarchy.Logger)logger ).Level = hier.LevelMap[strLogLevel];
        }
      }

      //Configure the root logger.
      log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository ();
      log4net.Repository.Hierarchy.Logger rootLogger = h.Root;
      rootLogger.Level = h.LevelMap[strLogLevel];
    }

    ///<summary>
    ///0 -- prints only FATAL messages 
    ///1 -- prints FATAL and ERROR messages 
    ///2 -- prints FATAL , ERROR and WARN messages 
    ///3 -- prints FATAL  , ERROR , WARN and INFO messages 
    ///4 -- prints FATAL  , ERROR , WARN , INFO and DEBUG messages 
    ///</summary>
    private static string GetLogTypeString ( DebugLevel debugLevel )
    {

      string srtLogLevel = String.Empty;
      switch (debugLevel)
      {
        case DebugLevel.Fatal_Msgs:
          srtLogLevel = "FATAL";
          break;
        case DebugLevel.Fatal_Error_Msgs:
          srtLogLevel = "ERROR";
          break;
        case DebugLevel.Fatal_Error_Warn_Msgs:
          srtLogLevel = "WARN";
          break;
        case DebugLevel.Fatal_Error_Warn_Info_Msgs:
          srtLogLevel = "INFO";
          break;
        case DebugLevel.Fatal_Error_Warn_Info_Debug_Msgs:
          srtLogLevel = "DEBUG";
          break;
        default:
          srtLogLevel = "FATAL";
          break;
      } //eof switch
      return srtLogLevel;

    } //eof GetLogTypeString


    /// <summary>
    /// The path where the configuration is read from.
    /// This value is set upon a call to ConfigureLogging().
    /// </summary>
    private string configurationFilePath;
    public void ConfigureLogging ()
    {
      lock (this)
      {
        bool configured = false;


        #region ConfigureByThePathOfTheEntryAssembly
        // Tells the logging system the correct path.
        Assembly a = Assembly.GetEntryAssembly ();

        if (a != null && a.Location != null)
        {
          string path = a.Location + ".config";

          if (File.Exists ( path ))
          {
            log4net.Config.DOMConfigurator.Configure (
              new FileInfo ( path ) );
            configurationFilePath = path;
            configured = true;
          }
          else
          {
            path = FindConfigInPath ( Path.GetDirectoryName ( a.Location ) );
            if (File.Exists ( path ))
            {
              log4net.Config.DOMConfigurator.Configure (
                new FileInfo ( path ) );
              configurationFilePath = path;
              configured = true;
            }
          }
        }
        #endregion ConfigureByThePathOfTheEntryAssembly


        #region ConfigureByWeb.config
        // Also, try web.config.
        if (!configured)
        {
          if (HttpContext.Current != null &&
            HttpContext.Current.Server != null &&
            HttpContext.Current.Request != null)
          {
            string path = HttpContext.Current.Server.MapPath (
              HttpContext.Current.Request.ApplicationPath );

            path = path.TrimEnd ( '\\' ) + "\\Web.config";

            if (File.Exists ( path ))
            {
              log4net.Config.DOMConfigurator.Configure (
                new FileInfo ( path ) );
              configurationFilePath = path;
              configured = true;
            }
          }
        }
        #endregion ConfigureByWeb.config


        #region ConfigureByThePathOfTheExecutingAssembly
        if (!configured)
        {
          // Tells the logging system the correct path.
          a = Assembly.GetExecutingAssembly ();

          if (a != null && a.Location != null)
          {
            string path = a.Location + ".config";

            if (File.Exists ( path ))
            {
              log4net.Config.DOMConfigurator.Configure (
                new FileInfo ( path ) );
              configurationFilePath = path;
              configured = true;
            }
            else
            {
              path = FindConfigInPath ( Path.GetDirectoryName ( a.Location ) );
              if (File.Exists ( path ))
              {
                log4net.Config.DOMConfigurator.Configure (
                  new FileInfo ( path ) );
                configurationFilePath = path;
                configured = true;
              }
            }
          }
        }
        #endregion ConfigureByThePathOfTheExecutingAssembly


        #region ConfigureByThePathOfTheCallingAssembly
        if (!configured)
        {
          // Tells the logging system the correct path.
          a = Assembly.GetCallingAssembly ();

          if (a != null && a.Location != null)
          {
            string path = a.Location + ".config";

            if (File.Exists ( path ))
            {
              log4net.Config.DOMConfigurator.Configure (
                new FileInfo ( path ) );
              configurationFilePath = path;
              configured = true;
            }
            else
            {
              path = FindConfigInPath ( Path.GetDirectoryName ( a.Location ) );
              if (File.Exists ( path ))
              {
                log4net.Config.DOMConfigurator.Configure (
                  new FileInfo ( path ) );
                configurationFilePath = path;
                configured = true;
              }
            }
          }
        }
        #endregion ConfigureByThePathOfTheCallingAssembly


        #region ConfigureByThePathOfTheLibIsStored
        if (!configured)
        {
          // Look in the path where this library is stored.
          a = Assembly.GetAssembly ( typeof ( Logger ) );

          if (a != null && a.Location != null)
          {
            string path = FindConfigInPath ( Path.GetDirectoryName ( a.Location ) );
            if (File.Exists ( path ))
            {
              log4net.Config.DOMConfigurator.Configure (
                new FileInfo ( path ) );
              configurationFilePath = path;
              configured = true;
            }
          }
        }
        #endregion ConfigureByThePathOfTheLibIsStored



      } //eof lock   
    } //eof method 



    /// <summary>
    /// Searches for a configuration file in the given path.
    /// </summary>
    private string FindConfigInPath (
      string path )
    {
      string[] files = Directory.GetFiles ( path );

      if (files != null && files.Length > 0)
      {
        foreach (string file in files)
        {
          if (Path.GetExtension ( file ).Trim ( '.' ).ToLower (
            CultureInfo.CurrentCulture ) == "config")
          {
            return file;
          }
        }
      }

      // Not found.
      return string.Empty;
    } //eof method 



    /// <summary>
    /// Remove dynamically appenders
    /// </summary>
    /// <param name="appenderName"></param>
    /// <param name="threshold"></param>
    public static void SetThreshold ( string appenderName, Level threshold )
    {
      foreach (AppenderSkeleton appender in LogManager.GetRepository ().GetAppenders ())
      {
        if (appender.Name == appenderName)
        {
          appender.Threshold = threshold;
          appender.ActivateOptions ();

          break;
        }
      }
    } //eof method 



  } //eof class 


} //eof namespace 
0
ответ дан 5 December 2019 в 17:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: