Archivi categoria: Technology

Parsing e Modifica dell’output stream di Asp.Net

Talvolta può rendersi necessario "trattare" l'output di una applicazione asp.net che non si vuole modificare o, come nel mio caso, di un'applicazione sviluppata da terzi e di cui non si hanno i sorgenti; esempi posono essere l'aggiunta di un footer a tutte le pagine, di tag nell'header, esigenze di highlighting, o come nel mi caso dove l'esigenza era la modifica della modalità secondo la quale vennivano creati tutti gli hyperlink presenti nella pagina, al fine di rimuovere l'eventuale presenza di token di sessione che il sistema automaticamente aggiungeva nella GET (questi parametri infatti penalizzano particolarmente la creazione di siti con requisiti di posizionamento nei motori di ricerca.)

Cercando la tematica nel web, avevo trovato un post di Dino Esposito il quale introduceva ad una possibile strada, la quale leggendo nei commenti, presentava pro e contro.

Ho trovato un buono spunto nel seguente articolo il quale spiega in maniera abbastanza dettagliata la modalità.

Essenzialmente la logica è quella di inserirsi nella pipeline .net tramite un modulo o un handler, andando ad assegnare un filtro all'oggetto Response del contesto attuale; infatti l'oggetto response presente nel context presenta uno stream in "write-only", e quindi rende impossibile accedervi e modificarlo.

In maniera più pratica, nel caso di modulo, è necessario intercettare l'evento context_BeginRequest:

public class AuthRemoveModule : IHttpModule
{

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler (context_BeginRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = ((HttpApplication)sender).Context;
        context.Response.Filter = new Filter(context.Response.Filter); 
    }

}

Nel caso invece di un handler, nel mio caso ho ereditato da System.Web.UI.PageHandlerFactory ed ho fatto l'override del metodo GetHandler

public class AuthRemoveHandler : System.Web.UI.PageHandlerFactory
{
    public override IHttpHandler GetHandler(HttpContext context, string
             requestType, string virtualPath, string path)
    {
        IHttpHandler handler;
        handler = base.GetHandler(context, requestType, virtualPath, path);
        context.Response.Filter = new Filter(context.Response.Filter);
        return handler;
    }

}

In entrambi i casi è stato impostato un filter, che per mia comodità è in una classe dello stesso namespace, il quale si occupa di fare l'override del metodo write.
Ogni qual volta un controllo della pagina effettuerà una write nell'oggetto response del contesto, verrà attivato il filtro affinchè ne faccia le sue opportune elaborazioni. 

Sostanzialmente, la classe si occupa di salvare in uno stream privato l'output del contesto, in quanto le operazioni di write possono essere più di una. Unica attenzione riguarda la verifica che l'output sia alla sua fine prima di procedere all'elaborazione del testo; in questa implementazione semplificata, banalmente si attende che sia stato scritto il tag </html>

internal class Filter : Stream
 {
     private Stream _inner;
     private StreamBuilter _toParse = new StreamBuilder (1024);
     internal Filter(Stream inner)
     {
         _inner = inner;
     }
     public override void Write(byte[] buffer, int offset, int count)
     {

         // Salvo la scrittura nello stream privato.
         String piece = Encoding.UTF8.GetString(buffer, offset, count);
         _toParse.Append(piece);

         // Verifico che sia stato già scritto il tag </html>
         // Altrimenti esco

         if (!Regex.IsMatch(piece, "</html>", RegexOptions.IgnoreCase))
             return;

         // Eseguo il match per rimuovere il link
         // es, cerco:
         //
auth=QvVB60r%2flnEijA2zEon1SldDD2crcE4QQgFuM7WU%2biA%3d

         String result = Regex.Replace(_toParse.ToString(),
           @"auth=[A-Za-z0-9%]*%[3][d]",
           new MatchEvaluator(RemoveFullSegment), RegexOptions.IgnoreCase);
         Byte[] all = Encoding.UTF8.GetBytes(result);
         _inner.Write(all, 0, all.GetLength(0));

     }

     private String RemoveFullSegment(Match match)
     {
         // Modifico il match come voglio o rimuovo tutto come nel mio caso
         return "";
     }

     public override
void
Flush()
     {         _inner.Flush();     } 
     public override long Seek(long offset, SeekOrigin origin)
     {         return _inner.Seek(offset, origin);     } 
     public override void SetLength(long value)
     {         _inner.SetLength(value);     } 
     public override int Read(byte[] buffer, int offset, int count)
     {         return _inner.Read(buffer, offset, count);     }

}

In questa maniera è possibile controllare le modalità di rendering della pagina.

Manca all'appello solo il pezzettorelativo alla configurazione del web.config
Il modulo e l'handler sono da utilizzare alternativamente.
Ovviamente il primo va a lavorare solo sulle pagine aspx. Il secondo va a lavorare su tutte le richieste che vengono processate dal runtime .net (ad esempio allegati o altri contenuti che vengono gestiti direttamente dal framework, come ad esempio fanno WSS e MOSS)

<system.web>
   <httpHandlers>
      <add verb="*" path="*.aspx"
             type="Alberto.Internet.AuthRemoveHandler"
             validate
="false"/>
   </httpHandlers>
   <httpModules>
      <add name="AuthRemoveModule"
        type="Alberto.Internet.AuthRemoveModule"/>
  
</httpModules>
</system.web>


 

Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats v2

Segnalo il rilascio di questo pacchetto che, dopo il primo rilasci l’anno scorso con la beta (segnalato anche da igor), è ora stato rilasciato ufficialmente.

Questo aggiornamento faciliterà non poco migrazioni alla nuova versione di office nelle aziende, facendo si che si possano introdurre soluzione avanzate ad alcuni utenti (con office 2007 + WSS) Facendo si che il resto dell’azienda non sia costretta a migrare e possa continuare ad usare la stessa versione di office.

http://www.microsoft.com/downloads/details.aspx?FamilyID=941b3470-3ae9-4aee-8f43-c6bb74cd1466&displaylang=en

.NET CF 2.0 SP2 e Performance

Come segnalato in questo post di rob, è uscito l’sp2 del compact framework.Oltre agli update elencati, segnalo un’enacement novole sul Performance Monitor (il quale in questa versione funziona anche su vista): è stao infatti aggiunta la possibilità di effettuare vari “snapshot” del GC Heap per poter monitorare il numero di oggetti, con la possibilità di comparare in un unica vista tutte le “fotografie”. Questo consente di verificare durante l’esecuzione dell’applicazione dell’andamento delle risorse.

gcheap6

Questa cosa proprio ieri mi ha fatto risparmiare un bel po’ di tempo nell’andare ad identificare un problema nella gestione delle connessioni al database

Per approfondimenti, date un’occhiata a questo post di Steven Pratschner.

Sql 2005 Reporting Service e autenticazione via form

Stiamo in questi giorni migrando una applicazione di un nostro cliente ad una nuova infrastruttura HW (dopo 5 anni di sudato lavoro i due server HP: LP2000r e TC4100, andranno in pensione, al loro posto due nuovissimi DL360 G5 Xeon 5160). Con l’occasione abbiamo previsto la migrazione del relativo modulo di reporting che avevamo implementato con Sql 2000 reporting service alla versione 2005. Il modulo prevede l’utilizzo di RS con form autentication e la definizione di un’interfaccia custom di selezione dei report e dei relativi parametri di filtro.

L’impostazione di base della nuova versione è sicuramente migliore, nella versione precedente si doveva sempre lavorare molto con i vari parametri di querystring da passare al webservice che di default si trova sotto /reportserver/. I nuovi controlli che sono già disponibili in visualstudio2005, permettono di inserire un controllo sia in un’applicazione web che winform con una semplicità estrema; fino a qui… tutto bene.

C’è una cosa però che mi spiego: nella versione winform (Microsoft.ReportViewer.WinForms) del controllo esiste un bellissimo metodo per effettuare l’autenticazione del report in maniera trasparente per l’utente
ReportViewer1.ServerReport.ReportServerCredentials.SetFormsCredentials(null, "UserName", "Password", "DomainName");

La stesso metodo però, non è disponibile se si usa l’oggetto ServerReport del namespace Microsoft.ReportViewer.WebForms.

Per ovviare a questa mancanza e autenticare trasparentemente l’utente, esistono degli esempi (pazzeschi come logica) dove la pagina web che esegue il reportviewer, ricevuta una richiesta di report, si deve connette al webservice del reportserver, effettuare l’autenticazione e recuperare il cookie relativo all’autenticazione ricevuto dal webservice; deve infine impostarlo nella response della pagina, inoltrandolo quindi al client chiamante (il browser dell’utente) in modo che i succssivi accessi (che sono diretti) riutilizzino le stesse credenziali per ai dati. Ma io mi dico, non potevano metterci a disposizione lo stesso metodo SetFormsCredentials del winform??

Per chi fosse interessato, un articolo di esempio per questa tecnica date una lettura a questo post: http://blogs.msdn.com/bimusings/archive/2005/11/04/489100.aspx

Riporto inoltre qualche altro puntatore a tema interessante:
http://msdn2.microsoft.com/it-it/library/microsoft.reporting.webforms.ireportservercredentials(VS.80).aspx
http://www.gotreportviewer.com/
http://www.devx.com/dotnet/Article/30424

Monitor e Produttività

Come sviluppate? Usate un unico monitor?
Un collega qualche tempo fa mi ha inviato qualche link su ricerche effettuate che dimostrerebber l’aumento di efficienza che si ottiene lavorando con monitor multipli. Questo aumento, secondo alcuni, può andare dal 9% al 50%, a seconda della tipologia di lavoro o attività.

Personalmente, da quanto ho attaccato un crt al mio portatile (che era rimasto inutilizzato in ufficio) non ne posso fare più a meno.
Voi cosa ne pensate? Se vi va, usate i commenti.

Riporto qualche riferimento:

 

Inoltre recentemente ho visto su un post questo:

workspace