A chiunque sviluppa applicazione medio – grandi è capitato di scontrarsi con la lettura di log file incomprensibili, spesso generati manualmente senza perderci troppo tempo che però portano a una conseguenza: è impossibile capire dove è l’errore .
Oggi è uno di questi giorni e stufo di perdere tempo a leggere log interminabili ho finalmente trovato una soluzione che mi soddisfa.
Ricapitoliamo velocemente quali sono le tecniche solitamente usate “per far presto”…
Veniamo ora alla soluzione a cui sono giunto, spesso mi ero domandato se in c# ci fossero interfacce predefinite adibite al logging e come utilizzarle anche in applicazione WCF. Andiamo con ordine.
La prima cosa è importare
using System.Diagnostics;
Debug.WriteLine(errorMessage);
<configuration> <system.diagnostics> <trace autoflush="true"> <listeners> <add name="debugListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="debug.txt" /> </listeners> </trace> </system.diagnostics> </configuration>
In automatico la stringa errorMessage passata come parametro sarà scritta anche nel file debug.txt(Cartella di progetto /bin / Debug). In questo modo avrai un log file con solo quello che ti interessa e nel formato che preferisci, si può infatti generare anche file XML.
La soluzione che ho sviluppato per l’utilizzo con WCF è ancora un po’ più raffinata. Sfrutta l’interfaccia IErrorHandler contenuta in System.ServiceModel.Dispatcher che espone i metodi:
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault);public bool HandleError(Exception error);
Il primo metodo viene chimata all’interno del' thread che solleva l’eccezione. Questo metodo può essere usato per fare una gestione centralizzata delle eccezioni, che sinceramente non mi convince a fondo, ma sicuramente ha dei vantaggi, o comunque può essere utlizzata per catturare le eccezioni non gestite o modificare l’eccezione generata automaticamente. Ogni eccezione invoca automaticamente questo metodo prima di ritornare al chiamante.
Il secondo metodo è invece eseguito da in un thred separato rispetto a quello in cui viene sollevata l’eccezione e può essere usto per gestire il logging dell’applicazione.
Ora il codice completo:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using System.Diagnostics; using System.ServiceModel; using System.ServiceModel.Channels;namespace WcfSecureService { class SSErrorHandler : Attribute, IErrorHandler, IServiceBehavior { #region IErrorHandler Members public bool HandleError(Exception error) { //Error logging. Debug.WriteLine("Eccezione Sollevata:"); string errorMessage = string.Format("Application:{0},method:{1},StackTrace:{2}", error.Source, error.TargetSite.Name, error.StackTrace); Debug.WriteLine(errorMessage); return true; } public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault) { // Gestione centralizzata delle eccezioni. Tutte le eccezioni passano di qui e possono essere modificate // prima della spedizione. //if (error is NullReferenceException) { // // Creates a message fault. // MessageFault messageFault = exception.CreateMessageFault(); // fault = Message.CreateMessage(version, messageFault, exception.Action); //} } #endregion #region IServiceBehavior Members public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach (var channelDispatcherBase in serviceHostBase.ChannelDispatchers) { var channelDispatcher = channelDispatcherBase as ChannelDispatcher; channelDispatcher.ErrorHandlers.Add(new SSErrorHandler()); } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } #endregion } }
La seconda parte può non essere implementata, sfruttando così le impostazioni di default di WCF.
Ciao,
Matteo
Complimenti.
Ottimo
Stavo appunto cercando qualcosa di sensato e usabile per loggare.
ora provo nella pratica ad usare i tuoi suggerimenti ma mi sembrano molto buoni!
Grazie