Press "Enter" to skip to content

4 – Classi di uso comune

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.