Creare un HttpHandler per la gestione delle immagini in ASP.NET

Giorgio Borelli

Creare un httphandler personalizzato per il ridimensionamento automatico delle richieste riguardanti le immagini in asp.net Gli HttpHandler sono gli oggetti del motore di ASP.NET responsabili della gestione della risposta in seguito alle richieste dei client.

Conoscere il funzionamento degli HttpHandler di ASP.NET permette di gestire come si vuole le risposte da dare alle richieste dei client, in quanto è possibile tramite il web.config associare un path ai tipi di risorse (file) che si vuole gestire con il proprio personalissimo HttpHandler.

La funzionalità degli HttpHandlers è davvero straordinaria, se ci pensiamo bene, ASP.NET mette in mano dei programmatori un potere grandissimo, quello di poter gestire come si vuole le risorse da presentare ai client. In questo modo ad esempio è possibile creare dei personali HttpHandlers per la gestione di file, report, e di qualsiasi altra risorsa web di cui la nostra applicazione web necessita, senza nemmeno interessarci di come questa effettivamente funzioni. A tal proposito, in questo articolo, proveremo ad implementare un HttpHandler per il ridimensionamento automatico delle immagini di un'applicazione Web scritta in ASP.NET.

Gli HttpHandlers sono delle classi (file con estensione ashx) che implementano l'interfaccia IHttpHandler, la quale definisce un metodo ed una proprietà:

public interface IHttpHandler {
    void ProcessRequest(HttpContext context);  

    bool IsReusable { get; }
} 

Il metodo ProcessRequest prende come parametro l'oggetto della richiesta, ovvero l'HttpContext, mentre la proprietà IsReusable indica un valore booleano per il riutilizzo o meno della classe responsabile della risposta nel soddisfacimento delle ulteriori richieste.

Sfruttando il meccanismo degli HttpHandler possiamo quindi creare una classe che ci permetta di gestire tutte le richieste inerenti le immagini del nostro sito. Con tale tecnica possiamo passare il nome delle immagine e la sua dimensione direttamente in querystring, con un URL del tipo http://www.miosito.com/nomeimmagine.jpg?Size=128, siamo in grado di gestire questa richiesta e fornire l'immagine ridimensionata automaticamente con i parametri passati.

Aggiungiamo allora all'interno del nostro progetto web un file ashx, posizionandolo o nella root del sito o meglio ancora nella cartella App_Code, ed al suo interno definiamo la classe HandlerImage facendola derivare dall'interfaccia IHttpHandler descritta pocanzi. Nell'implementazione della classe (il nostro HttpHandler) per la proprietà IsReusable facciamo ritornare il valore false, mentre nel metodo ProcessRequest andremo ad implementare il codice necessario per la gestione automatica delle immagini che vogliamo realizzare.

Andiamo a vedere l'intero codice del nostro HttpHandler per la gestione delle immagini, dopodichè ne analizzeremo le parti più salienti:

<%@ WebHandler Language="C#" Class="HandlerImage" %>
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;

public class HandlerImage : IHttpHandler {

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    public void ProcessRequest (HttpContext context) {
        // Setup the response settings
        context.Response.ContentType = "image/jpeg"; //imposto il Contenuto della risposta su jpeg
        context.Response.Cache.SetCacheability(HttpCacheability.Public);
        context.Response.BufferOutput = false; //disattivo il buffer di output

        //variabile per contenere il nome dell'immagine
        string nameImg = string.Empty;

        if (context.Request.QueryString["NameImg"] != null && context.Request.QueryString["NameImg"] != string.Empty)

            nameImg = context.Request.QueryString["NameImg"]; //dopo il check, assegno il nome presente in querystring

        //variabile per la dimensione (width) dell'immagine
        int targetSize = 0;

        if (context.Request.QueryString["Size"] != null && context.Request.QueryString["Size"] != string.Empty)

            targetSize = Convert.ToInt16(context.Request.QueryString["Size"]);  //dopo il controllo assegno la dimensione presente in querystring

        //inizializzo il path e lo stream dell'immagine
        string pathImg = string.Empty;
        Image imgStream = null;

        try
        {
            //assegno il path dell'immagine
            pathImg = ManagerSettings.GetVirtualPathImages + nameImg;

            //controllo se il file immagine esiste
            if (File.Exists(context.Server.MapPath(pathImg)))
            {
                //creo l'immagine dal file
                imgStream = System.Drawing.Image.FromFile(context.Server.MapPath(pathImg));
            }
            else
            {
                //imposto il path a quello di default (un'immagine di default NO-IMAGE)
                pathImg = ManagerSettings.GetNoImages;
                imgStream = System.Drawing.Image.FromFile(context.Server.MapPath(pathImg));
            }
        }

        catch
        {
            //creo l'immagine col file no-image di default
            pathImg = ManagerSettings.GetNoImages;
            imgStream = System.Drawing.Image.FromFile(context.Server.MapPath(pathImg));
        }

        // Se nella querystring non era specificata la dimensione assegno quella originale
        if (targetSize == 0)
            targetSize = imgStream.Width;

        //creo una nuova bitmap ridimensionandolo con le misure passate nella query string
        Bitmap img = new Bitmap(HelperImage.ResizeImageFile(imgStream, targetSize));

        //salvo l'immagine ridimensionata nell'output della risposta in formato jpeg
        img.Save(context.Response.OutputStream, ImageFormat.Jpeg);
    }
}

Il codice mostrato, in sostanza non fà altro che impostare il contenuto della risposta sull'estensione jpeg e disattivare il buffer di output per evitare sovraccarichi in caso di file di grosse dimensioni. Dopo si passa ad analizzare e ricavare i parametri in querystring, il primo per il nome del file immagine richiesto ed il secondo per la sua dimensione, queste due informazioni vengono assegnate a due variabili locali, rispettivamente nameImg e targetSize, dal nome immagine se ne ricava il file verificando che esiste nel path specificato, diversamente viene caricata una immagine di default (NO-IMAGE) predisposta precedentemente. Avendo il file se ne crea lo stream e lo si dà in pasto al metodo ResizeImage con il target size specificato, in questo modo l'immagine viene ridimensionata ed assegnata come bitmap, infine si restituisce lo stream dell'immagine nell'output della risposta in formato jpeg, più leggero e facile da trattare.

Le classi ManagerSettings ed HelperImage sono due mie classi statiche che uso rispettivamente per gestire i path e le impostazioni generali delle mie applicazioni e per l'uso delle immagini, al di là di questo prendere questo codice ed adattarlo alle proprie pagine è abbastanza semplice. Potete richiamare questo handler direttamente dal markup delle vostre pagine aspx, in una gridview o in una pagina di dettaglio, passando le dimensioni volute per le immagini, che si ridimensioneranno in automatico risparmiandovi un sacco di lavoro, ad es. in questo modo:

<img src="~/HandlerImage.ashx?NameImg=<%# Eval("Image") %>&Size=48" />

 

Cominciate ad apprezzarne le potenzialità? Ma possiamo fare di più, possiamo referenziare il nostro HandlerImage per la gestione delle immagini direttamente nel web.config, così in automatico tutte le immagini richieste saranno gestite da esso, per far questo sotto system.web aggiungiamo un path per le immagini dentro il nodo httphandler, in questo modo:

<system.web>
    ...
    <httpHandlers>
        <addverb="*"path="*.jpg"type="HandlerImage, App_Code"/>
    </httpHandlers>
    ...
</system.web>

Il parametro "verb" specifica il tipo di richiesta per la quale deve essere usato questo handler (GET, POST, * per tutte), "path" indica per quali tipi di file, in questo caso abbiamo detto solo per le jpg e "type" referenzia il nome dell'HttpHandler e l'assembly (App_Code) che deve gestire queste tipo di risposte.

Volendo, anzichè inserire l'HttpHandler per le immagini nella cartella App_Code o nella route del sito, possiamo crearci una libreria esterna che lo contenga e referenziare questa per i futuri progetti web che dovranno far uso di esso, in questo modo aumentiamo anche la manutenibilità e la scalabilità del codice stesso.

 

Chiunque voglia aggiungere qualcosa in merito all'argomento, porre una domanda o dare un suggerimento, ogni commento è ben accetto.

Categorie: ASP.NET | C#

Tags:

Commenti (2) -

Ciao,
ho letto il tuo interessantissimo articolo,
tuttavia provando quando registro sul web config la seguente stringa:
<httpHandlers>
      <add path="*aspx" verb="*" type="Handler, App_Code" />

    </httpHandlers>

Mi esce fuori il seguente errore:
Impossibile caricare il file o l'assembly 'App_Code' o una delle relative dipendenze. Impossibile trovare il file specificato.

Sapresti aiutarmi?? GRAZIE
    

Rispondi

prova così:

<system.web>
    <httpHandlers>
      <add verb="*" path="*.aspx"
         type="Handler" />
    </httpHandlers>
</system.web>

Fammi sapere se funziona, ciao Giorgio.

Rispondi

Pingbacks and trackbacks (1)+

Aggiungi Commento

biuquote
Loading