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, già all'avvio dell'applicazione 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'atto dell'avvio 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 già istanziato la nostra classe ServiceA e eseguiremmo 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:

[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.

venerdì 24 ottobre 2014

[C#] Configurare e utilizzare LOG4NET per scrittura su file

A volte capita di dover integrare un meccanismo di logging all'interno della nostra applicazione. A tal proposito trovo molto comoda la libreria LOG4NET di Apache scaricabile qui per creare i log in applicazioni .net, per chi di voi conoscesse già LOG4J non ci sono molte differenze nella configurazione di questa libbreria. 

Oggi vedremmo come configurarla e sfruttarla nelle nostre applicazioni .net, per iniziare dobbiamo scaricare la libreria e successivamente aggiungere il riferimento alla nostra applicazione, ricordiamoci di far copiare localmente a Visual Studio la libreria, in caso contrario se esporteremo il progetto avremmo dei problemi a causa della libreria mancante. 

Successivamente dovremmo configurare il file AssemblyInfo.cs aggiungendo la seguente riga:

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Web.config", Watch = true)]   

tale riga ci permette di dire a LOG4NET dove si trova la configurazione da utilizzare per costruire i log, se si tratta di una web application tale file comunemente è il WEB.CONFIG nel caso di applicazioni si tratta del file APP.CONFIG. 

Dopo di che andremmo a inserire nel file Web.config la configurazione dei log nella sezione <configuration>:

Nota bene: il seguente codice deve essere inserito immediatamente sotto al tag di apertura di configuration in caso negativo si avrà un'errore. 

<configSections>
    <!-- Add log4net config section-->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
<log4net debug="true">
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="Log\log.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
      </layout>
    </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingLogFileAppender" />
    </root>
  </log4net>

come potete vedere la configurazione ci permette di indicare la posizione del file di log tramite il tag <file value="Log\log.txt" /> e la sua dimensione massima tramite il tag <maximumFileSize value="10MB" />. La parte più importante è il tag <level value="DEBUG" />, questo tag indica il livello nel quale LOG4NET inizia a scrivere i log nel file di log, in ordine di importanza i livelli disponibili sono: DEBUG, INFO, WARNING, ERROR. Nel nostro caso LOG4NET è configurato per scrivere tutti i tipi di log. 

Infine all'interno del nostro codice c# dovremmo aggiungere la dichiarazione globale nella classe da sottoporre a logging:

private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 
ricordandoci di aggiungere using Log4Net, mentre nel nostro codice andremmo a inserire il seguente codice:

log.Error(ex.Message);

nell'esempio che segue ho inserito sia un log informativo sia un log di errore.

public DataTable StrSqlToDataTable( String sqlStr)
        {
            DataTable dt = new DataTable();
            SqlConnection cnn = new SqlConnection(connStr);
            try
            {
               
                cnn.ConnectionString = connStr;
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = cnn;
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = sqlStr;
                if (cnn.State != ConnectionState.Open)
                {
                    cnn.Open();
                }
                dt.Load(cmd.ExecuteReader());
               
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);            }
            finally {
                cnn.Close();
                cnn.Dispose();
                log.Info("Eseguita query: " + sqlStr);            }
           
            return dt;
        }

Come potrete vedere LOG4NET ci offre molte possibilità per creare dei log completi.

Come al solito spero di essere stato di aiuto.