2009-10-10 5 views
2

J'ai une simple application de test winform que j'utilise pour essayer des trucs Log4Net Dependency Injection.J'ai essayé de faire fonctionner Log4Net avec Dependency Injection

J'ai fait une interface simple dans mes services projet: -

public interface ILogging 
{ 
    void Debug(string message); 

    // snip the other's. 
} 

Ensuite, mon type de béton utilisera Log4Net ...

public class Log4NetLogging : ILogging 
{ 
    private static ILog Log4Net 
    { 
     get { return LogManager.GetLogger(
         MethodBase.GetCurrentMethod().DeclaringType); } 
    } 

    public void Debug(string message) 
    { 
     if (Log4Net.IsDebugEnabled) 
     { 
      Log4Net.Debug(message); 
     } 
    } 
} 

Jusqu'à présent, si bon. Rien de trop dur là-bas.

Maintenant, dans un autre projet (et donc namesapce), j'essaie d'utiliser cette ...

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     FileInfo fileInfo = new FileInfo("Log4Net.config"); 
     log4net.Config.XmlConfigurator.Configure(fileInfo); 
    } 

    private void Foo() 
    { 
     // This would be handled with DI, but i've not set it up 
     // (on the constructor, in this code example). 
     ILogging logging = new Log4NetLogging(); 
     logging.Debug("Test message"); 
    } 
} 

Ok .. aussi assez simple. J'ai codé en dur l'instance ILogging mais c'est généralement une dépendance injectée via le constructeur. Quoi qu'il en soit, quand je vérifie cette ligne de code ...

return LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

la valeur de type DeclaringType est de l'espace de noms service , pas le type de formulaire (ie. XYZForm1) qui en fait appelé la méthode . Sans passer la méthode INTO comme un autre argument, y a-t-il de toute façon recours à la réflexion pour trouver la méthode real qui l'a appelée?

Répondre

0

Pour obtenir l'objet MethodInfo qui appelle une méthode particulière, vous devez examiner la pile d'appels. Cela peut être accompli par la classe StackTrace de la manière suivante.

using System.Diagnostics; 
using System.Reflection; 

public class Log4NetLogging : ILogging 
{ 
    private ILog GetLogForStackFrame(StackFrame frame) 
    { 
     return LogManager.GetLogger(frame.GetMethod().DeclaringType); 
    } 

    public void Debug(string message) 
    { 
     ILog log = GetLogForStackFrame(new StackTrace().GetFrame(0)); 
     if (log.IsDebugEnabled) 
     { 
      log.Debug(message); 
     } 
    } 
} 

Sur une note côté, je considère modifier votre interface pour accepter la Type de l'objet qui utilisera le journal abstrait. Je me rends compte que vous ne voulez pas faire cela, mais la récupération de la pile d'appels à l'exécution est une opération coûteuse et devra être effectuée chaque fois que vous appelez ILogging.Debug.

+0

acclamations, je j'y vais et essayez ceci. J'avais peur que vous alliez dire que cette réflexion était chère. D'un côté, qu'est-ce que 'GetLogger (string)' fait ... cherche-t-il une valeur d'entrée de configuration => ... .. donc en théorie, je pourrais juste passer dans une chaîne manuelle ici .. et assurez-vous qu'il existe dans le fichier de configuration? –

+0

La documentation sur 'GetLogger (string)' n'est pas très utile, mais elle suggère que la configuration du journal est extraite du fichier de configuration. Si cela est vrai, vous pouvez remplacer le code "get-logger-for-type-T" par un appel "get-logger-by-name", comme vous l'avez suggéré, et configurer le logger nommé pour le type T dans le fichier de configuration . Pour plus d'informations, voir http://logging.apache.org/log4net/release/sdk/log4net.LogManager.GetLogger_overload_1.html pour plus d'informations. –

+0

Oui. il m'a fallu _AGES_ pour que cela fonctionne, mais si vous avez ..., alors vous pouvez faire GetLogger ("Bonjour"). Ce qui m'a pris de l'âge pour le faire fonctionner, c'est que c'est _CASE BLOODY SENSITIVE_. donc je faisais GetLogger ("hello") et ça renvoyait le logger par défaut/root :(Zut! –

1

une réponse supplémentaire qui pourrait aider quelqu'un
suite à la suggestion de Steve je changé ma mise en œuvre du service de journalisation pour avoir un constructeur qui accepte un type à savoir l'argument de type à fournir dans la méthode journal tel que spécifié dans l'interface ILogger

public class MyLogging_Service : IMyLogging_Service 
{ 
    private Type _declaringType; 
    private ILog _log; 
    private ILog Log { get { return _log; } } 

    public MyLogging_Service(Type p_Val) 
    { 
     _declaringType = p_Val; 
     _log = LogManager.GetLogger(p_Val); 
    } 

    public void LogInfo(string p_Msg) 
    { 
     Log.Logger.Log(_declaringType, Level.Info, p_Msg, null); 
    } 

... 

} 

utilisation réelle

public class Service1 : IService1 
{ 
    // declared as a property 
    IMyLogging_Service MyLoggingService { get; set; } 

} 

avant que je StructureMap pour remplir cette propriété automatiquement à l'aide injection setter
voir link

dans mon injection de dépendance bootstrapper je l'ai utilisé la déclaration suivante

FillAllPropertiesOfType<IMyLogging_Service>().TheDefault.Is 
       .ConstructedBy(context => new MyLogging_Service(context.ParentType)); 

pour récapituler
1.
2. créé une propriété de service de consignation pour une classe qui doit avoir une fonctionnalité de consignation
3. code inclus dans la classe de création d'une classe pour implémenter la consignation à l'aide d'un constructeur acceptant un type à utiliser pour spécifier l'argument callerStackBoundaryDeclaringType l'injection de dépendance bootstrapper pour remplir la propriété avec le type de parent à l'aide du contexte StructureMap variables

BTW dans les cas dans votre code où DI n'est pas nécessaire, alors vous pouvez écrire du code comme ceci

new MyLogging_Service(this.GetType()) 
Questions connexes