mercoledì 11 gennaio 2017

[.NET] Elmah Logging


Tempo fa, parlando con dei colleghi sui progetti che stavano sviluppando e per scambiarci qualche idea per agevolare lo sviluppo iniziammo a parlare di logging di errore e di come in fase di sviluppo, già dalle prime battute, fosse importante cercare di avere un log accurato e di facile lettura. 

Di tool di logging ce ne sono molti, log4net di cui ho già parlato parecchio tempo fà è uno di quelli, ma richiedono di implementare nel codice delle istruzioni per permettere a questi tool di fare il proprio lavoro, dall'altro lato, creare un'algoritmo personalizzato per la scrittura del codice è un'altra pratica comune.  

Uno di questi miei colleghi ci spiegò che su un progetto dove stava lavorando utilizzavano un tool per il log di errore molto particolare, che permetteva, senza scrivere nemmeno una riga di codice, di tener traccia di tutti gli errori che potevano accadere durante l'esecuzione del codice. Che era di facile lettura, molto accurato, preciso e che dava la possibilità di scrivere l'errore sia su file, sia su DB, che permetteva di inviare mail a un'indirizzo Email tale log e che tramite una pagina precostruita dal tool stesso forniva una vista di tutti gli errori generati; Tale tool era Elmah creato da Atif Aziz


Cos'è Elmah
Elmah (così come ci spiega lo sviluppatore nella home page del progetto) è un tool per la gestione del log degli errori completamente automatizzato e facilmente configurabile.

Può essere configurato per scrivere su i seguenti DB:
Ed oltre ad essere completamente open source è facile da configurare sul proprio progetto.

Come configuriamo Elmah
Configurare Elmah è molto semplice. 
Per iniziare scarichiamo la libreria da questa pagina, si tratta dell'ultima relase attualmente disponibile, dopo di che scarichiamo lo script per la creazione della tabella che Elmah utilizza per creare la tabella che andrà a popolare con i vari log, se utilizziamo SqlServer è questo qui.

Dopo aver lanciato lo script sul nostro DB e avendo verificato che tutto sia andato a buon fine avremmo la tabella ELMAH_Error e le Stored Procedures ELMAH_GetErrorXml, ELMAH_GetErrorsXml e ELMAH_LogError. Da notare che questo script inserirà le tabelle su lo schema [dbo].

Dopo di che apriamo il file web.config all'interno della nostra applicazione e eseguiamo le modifiche per dare a Elmah la possibilità di gestire i log di errore.

Le modifiche che illustrerò di seguito sono quelle per una configurazione della scrittura su DB e di invio Email.

Prima di tutto aggiungiamo in <configSections> il seguente <sectionGroup>

    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>

dopo di che inseriamo questa sessione:

<elmah>
      <security allowRemoteAccess="0" />
      <errorLog type="Elmah.SqlErrorLog, Elmah"
      connectionStringName="<Nome della Stringa di Connessione>" />
      <errorMail
      from="elmah@example.com"
      to="admin@example.com"
      subject="..."
      priority="Low|Normal|High"
      async="true|false"
     smtpPort="25"
     smtpServer="smtp.example.com"
     useSsl="true|false"
     userName="johndoe"
     password="secret"
     noYsod="true|false" />
 </elmah>

Questa sessione ci permette di configurare Elmah per la scrittura sul db e sull'invio delle email contenenti il log.

Successivamente inseriamo all'interno della porzione <HttpModules>

<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />

Mentre in <Modules> inseriremo questi moduli

<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />

Per finire inseriamo nella root del web config questa porzione di codice.

<location path="elmah.axd"> 
        <system.web>
            <httpHandlers>
                <add verb="POST,GET,HEAD"
                     path="elmah.axd"
                     type="Elmah.ErrorLogPageFactory, Elmah" />
            </httpHandlers>
            <authorization>
                <deny users="?" /> 
            </authorization> 
        </system.web>
        <system.webServer>
            <handlers>
                <add name="ELMAH"
                     verb="POST,GET,HEAD"
                     path="elmah.axd"
                     type="Elmah.ErrorLogPageFactory, Elmah"
                     preCondition="integratedMode" />
            </handlers>
        </system.webServer>
</location> 

Tale porzione è quella che ci permette di richiamare la pagina web per la visualizzazione degli errori tramite l'indirizzo <indirizzo del nostro progetto>/elmah.axd

Se tutto è configurato per bene, ogni qual volta viene riscontrato un'errore, ci verrà inviata una mail con l'errore riscontrato e tale errore sarà scritto anche nel DB nella tabella ELMAH_Error.

Conclusioni
Se avete esigenza di usare un DB diverso da SQLServer potete trovare gli script per il db che utilizzate alla seguente pagina. Se invece volete modificare, per le vostre esigenze, il file web.config potete dare un'occhiata a questo link che fornisce una vista di tutte le opzioni disponibili.  

giovedì 31 marzo 2016

IoC e Dependency Injection, breve panoramica e implementazione in ASP.NET MVC utilizzando Ninject

Di cosa parliamo oggi?

Oggi andiamo a vedere come utilizzare il pattern IoC(inversion of control) in ASP.NET MVC utilizzando le librerie Ninject e le estensioni Ninject.Web.CommonNinject.Web.Mvc. La prima estensione serve per poter usare la seconda, come scritto nelle linee guida, mentre la seconda ci offre il supporto completo di Ninject sull'infrastruttura MVC.

Un po' di basi, IoC e Dependency Injection: Cosa sono? Come funzionano? Quali solo i benefici nell'usarli?

Cosa sono?

Partiamo dall'inizio. 
L'inversione di controllo (Inversion of Control) o IoC, non è altro che la possibilità di rendere le componenti software del nostro progetto il più indipendenti possibile, togliendo la responsabilità di istanziare classi all'interno del codice e dandola ad una terza parte, nel nostro caso a Ninject, che creerà le istanze delle classi da noi usate, mentre la nostra classe le consumerà solamente. Mentre il Dependency Injection (DI) è uno dei vari modi di implementare l'IoC ed è quello che vedremmo in questo post. 
Gli altri modi di implementare IoC sono questi:

Come Funzionano?

Come già accennato prima possiamo dire che tramite la Dependency Injection una terza parte, chiamata per comodità Builder, ci permette di creare le istanze delle classi che decidiamo di passare sotto IoC. 
Cerchiamo di spiegarlo con dei disegni presi in prestito dalla pagina Msdn.

Dependency Injection
All'interno della nostra applicazione il Builder crea un'istaza di ServiceA eseguendo il binding con la sua interfaccia IServiceA. A questo punto la Classe ClassA, potrà usare in ogni dove i metodi di ServiceA utilizzando IServiceA. 
Nell'atto Pratico immaginiamo di avere un metodo getTemperatura() contenuto nella classe ServiceA.
Di solito nella nostra classe, non utilizzando l'IoC, avremmo:

IServiceA _utility = new ServiceA();
var a = _utility.getTemperatura();

Mentre utilizzando la DI, avremmo solo:

var a = _utility.getTemperatura();

Quali sono i benefici nell'usarli?

Il beneficio che io in prima persona ho trovato è stato quello di poter creare tramite la DI, in fase di sviluppo, delle classi "fittizie"  dove avevo implementato un'algoritmo che mi forniva un'oggetto di risposta alla chiamata, simulando in questa maniera il comportamento che avrebbe avuto tale metodo se implementato. In questa maniera era più semplice portare avanti lo sviluppo di alcuni componenti software che dipendevano da altri ancora non implementati o di modificare semplicemente tali comportamenti sostituendo nel binding del Builder l'associazione tra interfaccia e classe.

Ninject 

Ninject è uno dei tanti tool che si trovano in giro per eseguire la DI su di un progetto. Se si guarda in giro quasi tutti hanno sviluppato un tool simile, tra i più usati possiamo nominare:
ma oltre questi ce ne sono altri. 

Uso Ninject da circa un paio di mesi per un mio progetto personale, ma posso dirvi che mi sono trovato benissimo. La velocità e la semplicità di Ninject è disarmante, anche la preparazione dell'architettura è facilissima. Da notare che ho usato Ninject SOLO su un progetto MVC 5.

Per utilizzare Ninject dobbiamo solamente aggiungere il suo pacchetto nuget sul progetto web.


Selezionare la libreria Ninject.Web.Mvc, una volta che facciamo click su Aggiungi, ci verrà chiesto di installare anche altre librerie, tra le quali troviamo Ninject e Ninject.Web.Common.


Dopo aver aggiunto anche le ultime librerie vedremmo che nel nostro App_Start è stata creata una classe di nome NinjectWebCommon che non è altro che il Builder di cui abbiamo parlato nella teoria. Tale classe si occupa di creare il binding tra le classi e le interfacce utilizzando all'interno del metodo RegisterServices(IKernel kernel) la seguente sintassi:

kernel.Bind<IUtility>().To<Utility>();

Successivamente all'interno della classe dove vogliamo richiamare il nostro Utility inseriremo il seguente codice che creerà per noi la nostra istanza:

[Inject]
public IUtility _utility { get; set; }

Così facendo all'interno del nostro codice potremmo usare direttamente _utility.getTemperatura() senza dover istanziare ogni volta la classe Utility.

Conclusioni

Questo che ho presentato è solo uno dei modi di utilizzare ninject, a breve, tempo permettendo, inserirò anche un mini tutorial sulle funzioni avanzate di ninject che comprendono gli scope degli oggetti ed altre particolarità di questo strumento. 

lunedì 20 luglio 2015

[.NET - MVC] Bundling e Minification come implementarlo.

Di cosa si parla
In ASP.NET MVC sfruttando i meccanismi di Bundling e il Minification possiamo ridurre drasticamente, se usati insieme, il tempo di caricamento della nostra applicazione web aumentandone le performance.

Una breve panoramica
Il Bundling utilizza i meccanismi del .net per permetterci di comprimere il puntamento ai file Css o ai file Js in un'unica chiamata mentre il Minification ci permette di ridurre semplicemente la grandezza dei file puntati eliminando i righe vuote, commenti e altro.
Ogni volta che creiamo un progetto web MVC partendo dalla versione 4+ partendo dal template base,
Screenshot di creazione progetto web base

utilizziamo il meccanismo del Bundling e Minification.
La classe che si occupa di gestirli si trova sotto la cartella app_start del progetto e si chiama BundleConfig.cs, aprendo questa classe troviamo al suo interno già configurati di default i puntamenti alle librerie javascript di Jquery e ai loro css.
Struttura del nostro progetto
Come possiamo vedere,  la semantica del Bundling è molto semplice, si tratta di dare un nome fittizio ad un'insieme di link di librerie javascript che vogliamo raggruppare.

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));
Nell'esempio sopra, come potete vedere, la libreria jQuery presente nella cartella Scripts viene associata al link fittizio ~/bundles/jquery.
Da notare poi che nell'istruzione che troviamo sopra è presente il segna posto {version}, tale segnaposto è molto utile è viene interpretato in maniera differente in base a vari fattori, in particolare viene interpretata:
  • In ambiente di Relase come il .min della versione di jquery che è presente nella cartella di Scripts mentre in Debug come la versione non .min della libreria
  • Quando eseguiamo un'aggiornamento delle librerie con Nuget riconosce automaticamente il cambio della versione, dandoci a noi la tranquillità di non dover modificare il file ogni volta. 
Come si implementa?
Implementare questi due meccanismi è molto semplice.
Creando un progetto base siamo già avvantaggiati, poiché l'IDE Visual Studio implementerà il meccanismo di Bundling automaticamente.
Ma se volessimo implementarlo da noi?
Per cominciare creiamo una classe sotto la cartella App_start di nome BundlingConfig.cs che avrà tra gli using la System.Web.Optimization, contenente tutti i tipi e i metodi di cui abbiamo bisogno (Se si comincia con un progetto vuoto si dovrà recuperare da nuget il pacchetto Optimization ed inserire all'interno del web.config "<add namespace="System.Web.Optimization" /> "), e il metodo public static void RegisterBundles(BundleCollection bundles).
All'interno del metodo andremmo a implementare l'istruzione per  eseguire il Bundling delle libbrerie jQuery-ui nella nostra applicazione:

bundles.Add(new ScriptBundle("~/bundles/jqueryUI").Include(
                        "~/Scripts/jquery-ui-{version}.js"));
o nel caso dei suoi stili:
bundles.Add(new StyleBundle("~/Content/css").Include(
            "~/Content/themes/base/jquery.ui.core.css",
            "~/Content/themes/base/jquery.ui.resizable.css",
            "~/Content/themes/base/jquery.ui.selectable.css",
            "~/Content/themes/base/jquery.ui.accordion.css",
            "~/Content/themes/base/jquery.ui.autocomplete.css",
            "~/Content/themes/base/jquery.ui.button.css",
            "~/Content/themes/base/jquery.ui.dialog.css",
            "~/Content/themes/base/jquery.ui.slider.css",
            "~/Content/themes/base/jquery.ui.tabs.css",
            "~/Content/themes/base/jquery.ui.datepicker.css",
            "~/Content/themes/base/jquery.ui.progressbar.css",
            "~/Content/themes/base/jquery.ui.theme.css"));
Successivamente nel Global.asax nel metodo Application_Start() implementiamo il metodo che eseguirà la nostra classe BundlingConfig.cs così facendo:

BundlingConfig.RegisterBundles(BundleTable.Bundles);

in tal modo diciamo che ad ogni avvio della nostra applicazione dovremmo eseguire il nostro metodo creando così i nostri "Bundle".
A questo punto all'interno della nostra pagina andremo a inserire il link al nostro "Bundle":

@Scripts.Render("~/bundles/jqueryUI")

Best practice
Di norma per usare in modo corretto queste pratiche è quello di implementare i Bundle dei Css nel head della pagina mentre il Bundle js appena sotto il @RenderBody.
Il motivo più semplice è quello di non incorrere in eccezioni di oggetti richiamati nei javascript e non ancora istanziati nella pagina oppure di problemi di fouc.

Conclusioni
Potete trovare informazioni più precise sull'argomento qui e qua spero che questo breve articolo sia stato abbastanza esaustivo per iniziare o per darvi delle delucidazioni.
Ringrazio tutti quelli che mi seguono e che mi hanno mandato mail per chiedermi che fine avevo fatto in questo annetto circa e anche quelli che mi hanno aiutato.
Ricordo a tutti che per ogni informazione aggiuntiva, se ci sono degli errori nelle istruzioni presentate qui o semplicemente per aggiungere qualcosa è possibile farlo scrivendo al mio indirizzo mail o semplicemente commentando qui sotto.