Proseguiamo la serie di classi helper con una classe, anzi due che ci serviranno per produrre dei messaggi di log che potranno poi essere intercettati e inviati ad un file, ad un monitor TCP, oppure all’event viewer, creando un sistema centralizzato per la raccolta dei messaggi da utilizzare in fase di debug, oppure in fase di test di una applicazione.
Di questa strada, impariamo come creare un evento statico, una classe per fornire dati agli event handler ed una enumerazione.
Introduzione
In questa terza puntata, vedremo alcune cose che reputo piuttosto interessanti, imposteremo un sistema per loggare eventuali errori oppure per inserire messaggi di controllo all’interno del codice che possano poi essere gestiti e inviati ad un file di log o ad altro sistema per le verifiche su una applicazione. Useremo per questo un evento statico che costruiremo in base alle nostre esigenze, creeremo una classe EventArgument apposita e un’enumerazione, quindi si tratta di un articolo succoso, dal punto di vista del codice.
La struttura di base della classe
using System; using System.Collections.Generic; using System.Reflection; using System.Text; namespace Dnw.Base.Logger { public static class EventLogger { private static readonly string mClassName = System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name; } }
Imports System Imports System.Collections.Generic Imports System.Reflection Imports System.Text Namespace Dnw.Base.Logger Public NotInheritable Class EventLogger Private Sub New() End Sub Private Shared ReadOnly mClassName As String = _ System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name End Class End Namespace
Anche in questo caso, abbiamo creato una classe Statica, non ci serve un oggetto istanziabile per generare dei Log, anzi, al contrario abbiamo bisogno di un oggetto unico che sia accessibile da tutta l’applicazione.
L’enumerazione LogVerbosity
/// <summary> /// Livello di verbosità del log /// </summary> public enum LogVerbosity { /// <summary> /// Logga solo gli errori /// </summary> OnlyErrors = 1, /// <summary> /// Logga errori e warnings /// </summary> ErrorsAndWarnings = 2, /// <summary> /// Logga tutto /// </summary> All = 3 }
''' <summary> ''' Livello di verbosità del log ''' </summary> Public Enum LogVerbosity ''' <summary> ''' Logga solo gli errori ''' </summary> OnlyErrors = 1 ''' <summary> ''' Logga errori e warnings ''' </summary> ErrorsAndWarnings = 2 ''' <summary> ''' Logga tutto ''' </summary> All = 3 End Enum
Questa enumerazione sarà usata per indicare al logger la tipologia di log che vogliamo sia inviata alla destinazione questo ci permetterà ad esempio di poter inserire in una applicazione la possibilità di decidere il livello di log, così da permettere di monitorare un’eccezione piuttosto che verificare i percorsi più utilizzati attraverso il codice magari per decidere in quali punti intervenire per effettuare ottimizzazioni.
La classe SendMessageEventArgs
Per generare i messaggi di Log, utilizzeremo un evento, questo evento dovrà fornire a ciò che lo intercetta il messaggio e la sua tipologia, informativo, di avviso, di errore, pertanto dobbiamo creare una classe Event Argument che fornisca all’Event handler i dati che gli servono, non si tratta di una classe complessa, come la maggior parte delle classi per gli eventi.
L’Enumerazione MessageType
public enum MessageType { /// <summary> /// Informazione /// </summary> Info, /// <summary> /// Avviso /// </summary> Warning, /// <summary> /// Errore /// </summary> Error }
Public Enum MessageType ''' <summary> ''' Informazione ''' </summary> Info ''' <summary> ''' Avviso ''' </summary> Warning ''' <summary> ''' Errore ''' </summary> [Error] End Enum
Per prima cosa definiamo un’enumerazione che ci permetterà di indicare qual’è il tipo di messaggio, quindi se si tratta di informazione, avviso oppure errore.
using System; using System.Collections.Generic; using System.Text; namespace Dnw.Base.Logger { public class SendMessageEventArgs : System.EventArgs { private readonly string mMessage; private readonly MessageType mType; public SendMessageEventArgs(string pMessage, MessageType pType) { this.mMessage = pMessage; this.mType = pType; } public string Message { get { return (this.mMessage); } } public MessageType Type { get { return (this.mType); } } } public delegate void SendMessageEventHandler(object sender, SendMessageEventArgs e); }
Imports System Imports System.Collections.Generic Imports System.Text Namespace Dnw.Base.Logger Public Class SendMessageEventArgs Inherits System.EventArgs Private ReadOnly mMessage As String Private ReadOnly mType As MessageType Public Sub New(ByVal pMessage As String, ByVal pType As MessageType) Me.mMessage = pMessage Me.mType = pType End Sub Public ReadOnly Property Message() As String Get Return (Me.mMessage) End Get End Property Public ReadOnly Property Type() As MessageType Get Return (Me.mType) End Get End Property End Class Public Delegate Sub SendMessageEventHandler(ByVal sender As Object, ByVal e As SendMessageEventArgs) End Namespace
Come possiamo vedere, la classe è molto compatta, ha un solo costruttore con due parametri, il messaggio ed il suo tipo, due campi readonly, ovvero modificabili solo dal costruttore, due property che li espongono. Oltre a questo, un Delegate Pubblico che permette di utilizzarlo per lanciare gli eventi.
L’interno della classe EventLogger
I campi
Pure essendo una classe statica, l’EventLogger non è proprio come tutte le altre classi helper che abbiamo finora visto, infatti al suo interno oltre al classico mClassname, ha anche due campi:
private static LogVerbosity mVerbosity; public static event SendMessageEventHandler LogNewEntry;
Private Shared mVerbosity As LogVerbosity Public Shared Event LogNewEntry As SendMessageEventHandler
Come possiamo vedere, all’interno della nostra classe abbiamo un campo static (Shared) privato che indica la Verbosità che è stata selezionata per il logger, questo campo esposto da una opportuna proprietà permetterà di indicare all’applicazione quale livello di log vogliamo attivare.
Il secondo campo è il nostro Evento, la sua sola differenza rispetto ai normali eventi delle classi standard è che è statico, quindi può essere intercettato senza dover instanziare la classe semplicemente utilizzando il seguente codice:
EventLogger.LogNewEntry += new SendMessageEventHandler(EventLogger_LogNewEntry); static void EventLogger_LogNewEntry(object sender, SendMessageEventArgs e) { try { throw new Exception("The method or operation is not implemented."); } catch (Exception ex) { throw new ApplicationException(" " + mClassName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, ex); } }
AddHandler EventLogger.LogNewEntry, AddressOf EventLogger_LogNewEntry Private Shared Sub EventLogger_LogNewEntry(ByVal _ sender As Object, ByVal e As SendMessageEventArgs) Try Throw New Exception("The method or operation is not implemented.") Catch ex As Exception Throw New ApplicationException(" " + mClassName + "." _ + System.Reflection.MethodBase.GetCurrentMethod().Name, ex) End Try End Sub
Il codice di esempio, assegna un event handler al nostro evento statico e il metodo che lo intercetta.
La proprietà Verbosity
public static LogVerbosity Verbosity { get { return mVerbosity; } set { mVerbosity = value; } }
Public Shared Property Verbosity() As LogVerbosity Get Return mVerbosity End Get Set mVerbosity = value End Set End Property
Questa proprietà espone il campo privato che abbiamo predisposto e permette di modificare la verbosità dell’emissione del log.
Il metodo OnLogNewEntry
private static void OnLogNewEntry(SendMessageEventArgs e) { if (LogNewEntry != null) { // Invokes the delegates. LogNewEntry(null, e); } }
Private Shared Sub OnLogNewEntry(ByVal e As SendMessageEventArgs) RaiseEvent LogNewEntry(Nothing, e) ' Invokes the delegates. End Sub
Questo metodo privato è utilizzato per sollevare l’evento che abbiamo definito nel codice precedente.
Il Metodo SendMsg
public static void SendMsg(string pMessage, MessageType pMessageType) { SendMessageEventArgs args = new SendMessageEventArgs(pMessage, pMessageType); OnLogNewEntry(args); } public static void SendMsg(string pMessageBase, object[] pParams, MessageType pMessageType) { SendMsg(string.Format(pMessageBase, pParams), pMessageType); } public static void SendMsg(string pMessageBase, object pParam, MessageType pMessageType) { SendMsg(string.Format(pMessageBase, pParam), pMessageType); } public static void SendMsg(string pMessageBase, object pParam1, _ object pParam2, MessageType pMessageType) { SendMsg(string.Format(pMessageBase, pParam1, pParam2), pMessageType); } public static void SendMsg(string pMessageBase, object pParam1, object pParam2, _ object pParam3, MessageType pMessageType) { SendMsg(string.Format(pMessageBase, pParam1, pParam2, pParam3), pMessageType); } public static void SendMsg(string pClassName, MethodBase pMethod, Exception pEx) { string msg = ExceptionHelper.BuildMessage(pClassName, pMethod, pEx); SendMsg(msg, MessageType.Error); }
Public Shared Sub SendMsg(ByVal pMessage As String, ByVal pMessageType As MessageType) Dim args As New SendMessageEventArgs(pMessage, pMessageType) OnLogNewEntry(args) End Sub Public Shared Sub SendMsg(ByVal pMessageBase As String, ByVal pParams _ As Object(), ByVal pMessageType As MessageType) SendMsg(String.Format(pMessageBase, pParams), pMessageType) End Sub Public Shared Sub SendMsg(ByVal pMessageBase As String, ByVal pParam _ As Object, ByVal pMessageType As MessageType) SendMsg(String.Format(pMessageBase, pParam), pMessageType) End Sub Public Shared Sub SendMsg(ByVal pMessageBase As String, ByVal pParam1 As Object, ByVal _ pParam2 As Object, ByVal pMessageType As MessageType) SendMsg(String.Format(pMessageBase, pParam1, pParam2), pMessageType) End Sub Public Shared Sub SendMsg(ByVal pMessageBase As String, ByVal pParam1 As Object, ByVal _ pParam2 As Object, ByVal pParam3 As Object, ByVal pMessageType As MessageType) SendMsg(String.Format(pMessageBase, pParam1, pParam2, pParam3), pMessageType) End Sub Public Shared Sub SendMsg(ByVal pClassName As String, ByVal pMethod As _ MethodBase, ByVal pEx As Exception) Dim msg As String = ExceptionHelper.BuildMessage(pClassName, pMethod, pEx) SendMsg(msg, MessageType.[Error]) End Sub
Per poter trasmettere al logger i loro messaggi, le classi delle nostre applicazioni possono avere necessità di passare i dati del messaggio in vari modi, abbiamo quindi implementato una serie di Overload dello stesso metodo con vari parametri.
Conclusioni
Abbiamo costruito qualcosa di interessante, ma non siamo ancora in grado di veder funzionare le classi della nostra libreria, vi chiedo di pazientare ancora un poco, poi potremo fare dei test, dobbiamo parlare di eccezioni e di nomi di File e cartelle, poi lo scheletro della nostra prima libreria conterrà il codice sufficiente ad effettuare dei test.
Per qualsiasi Feedback, Ulteriore domanda, Chiarimento, oppure se trovate qualche errore usate direttamente il form di contatto con un click sulla bustina in cima alla pagina.
Potete scaricare il progetto esempio dedicato alle classi di uso comune dal link qui sotto indicato.