martedì 23 febbraio 2010

Web Services C# to Php Pages

Mi porto dietro quest'idea da parecchio tempo, e la teoria nasce dall'esigenza di realizzare una web application ad alta integrazione. Che sia "davvero dinamica" che possa davvero crescere, indipendentemente dalla logica, ovviando a
tutte le costrizioni che l'ambiente .Net rischia di creare.

Con costrizioni intendo "ricompilazione di tutto il sito", revisione dei puntamenti, implementazione di tanto codice per
l'ottimizzazione e tutto quello che ne è correlato.

In ambiente .Net realizzando una web application si ha come output un "sito" e pur pensando alla generallizzazione
delle primitive o dei web controls pur cercando di "disaccopiare" dati e logica, si otterà una soluzione dove per aggiungere
pagine si è costretti a ricompilare tutto.

Ho quindi pensato di Staccare il "sito" da chi fornisce i dati, e chi segue il mio blog, si sarà accorto che soprattutto negli
ultimi post ho fatto qualche breve analisi su quel che mi poteva servire...

Ho pensato ad una Business Logic realizzato da web services in c# e le web page realizzate in php.

Grazie a jQuery è possibile "con uno sforzo iniziale un po' più sostanzioso" ottenere dei risultati decisamente buoni.

Il concetto di base è semplice:
php web page in post chiamata ajax ottiene l'xml dal web services.

E' possibile che la pagina contenga oggetti php che sappiano tradurre l'xml in quanto serve realmente mostrare.

Va da se che oggi l'esecutore della chiamata è una pagina php, ma parlando per Astrazioni è possibile che l'inteprete
dell'xml possa essere qualsiasi altra "Entità".


Integrazione con il project management... In perfetto stile "Agile" sfruttando questa logica d'implementazione si
ha un altro grosso vantaggio. Ogni funzionalità è "FINALIZZATA" è può essere verificata / testa / accettata / chiusa
senza impatti sul resto della soluzione.

Volete saperne di più ? contattatemi via mail.

lunedì 22 febbraio 2010

Div posizioni assolute e relative.....

Comprendo (div)entar matti, ma esagerare non fa bene alla salute.

Questo mini tutorial vi spiega come funzionano i vari allineamenti sfruttando
css Position.

Partiamo da una cosa semplice

Per ottenere questa pagina vi basta realizzare 4 div
1) {width:100%;height:100%}
2) {margin:0 auto;width:960px;background-color:yellow;}
3) {width:100px;height:100px;background-color:red;}
4) {width:100px;height:100px;background-color:lime;}

1) contiene 2)
2) contiene 3) e 4)

così:



Spostiamo il blocco verde

1) {width:100%;height:100%}
2) {margin:0 auto;width:960px;background-color:yellow;}
3) {width:100px;height:100px;background-color:red;float:left}
4) {width:100px;height:100px;background-color:lime;}



Spostiamo il Rosso al posto del verde
1) {width:100%;height:100%}
2) {margin:0 auto;width:960px;background-color:yellow;}
3) {width:100px;height:100px;background-color:red;float:right}
4) {width:100px;height:100px;background-color:lime;}

Rosso e verde uno sull'altro ..
1) {width:100%;height:100%}
2) {margin:0 auto;width:960px;background-color:yellow;}
3) {position:absolute;left:50;width:100px;height:100px;background-color:red;}
4) {width:100px;height:100px;background-color:lime;}

Rosso e verde uno sull'altro, ma in un altro modo.
1) {width:100%;height:100%}
2) {position:relative;margin:0 auto;width:960px;background-color:yellow}
3) {position:absolute;width:100px;height:100px;background-color:red;}
4) {position:absolute;top:10;width:100px;height:100px;background-color:lime;}


Non c'e' troppa chiarezza, quanto meno non è sempre specificato dove Mettere il RELATIVE. Ho fatto parecchie prove prima
di questo mini tutorial per comprendere quanto le posizioni siano "evanescenti".

Specificando nel div contenitore 2) il relative implica che tutti i div ( conenuti e con stile absolute ) faranno riferimento
alla posizione 0,0 (angolo in alto a sinitra).

Tutto quello che contine d4 non subirà variazioni, ma seguira la posizione in cui questo si trova.

giovedì 18 febbraio 2010

Decorator

Fra tanti pattern utili il decorator troneggia, anche se potrebbe non esser sempre chiaro lo scopo, o dove come quando applicarlo.

Tecnicamente parlando il decorator non fa altro che "estendere una base" e aggiungere "qualcosa".

Nel caso in esempio, esiste una classe Generic Item che è descritta da due proprietà e due metodi.
Le proprietà appartengono a Generic Item
I metodi sono virtuali (ossia) esiste la firma e volendo il codice del metodo, ma potrà essere esteso.

La classe book, estende Generic Item aggiunge due proprietà ed esegue l'override dei due metodi.
La classe brochure , estende Generic Item aggiunge una proprietà ed esegue l'override dei due metodi.

E' pur logico che il modo di Editare un libro sia diverso dal modo di Editare una brochure e tanto vale anche
per il modo in cui esse verranno visualizzati.

La classe astratta decorator ha un compito Creare Oggetti che abbiano come BASE Generic Item.

La classe coDecorator effettuerà il management di ciò che il decorator ha creato.

Ciò Detto ..
E' facile intuire quanto sia semplice individuare i casi d'uso, il rischio e che offuscati dalla voglia di utilizzare questo
pattern lo si "infili" un po da tutte le parti.

Un caso comune potrebbe essere la necessità di aggregare ad una classe Entity le sue derivate.

Utente e Utente Esteso
la classe utente (la nostra Generic Item ) contiene Nome Cognome, Login, Password
la classe utente Esteso (la nostra brochure o book) contiene in più Numero matricola, interno telefonico, sede di lavoro...

I dati della prima classe risiedono sulla tabelle Utenti mentre i dati di utente esteso potrebbero provenire da Ldap.

Per cui in Decorator creeremo UtenteEsteso e in coDecorator Popoleremo i dati.

WHERE 1=1

Per meglio dire quando barare via SQL.

Supponiamo che per un motivo qualsiasi abbiate realizzato un QueryHelpers che fra i suo metodi presenti AddContidion
e (sempre basandoci su una supposizione) la firma sia simle a questa:

public static string AddCondition(string OriginlQuery, string fieldName, string fieldValue, string Caluse)

Supponiamo (sempre) che il metodo verifichi prima che la sintassi sia corretta, che poi aggiunga la condizione
costruita più o meno così Caluse fieldName = fieldValue
dove Caluse può essere AND OR

Questo metodo potrebbe andare più o meno sempre... e per altro Va, ma davanti a query un po più complesse, si presentano
i primi problemi..
se per esempio ci si imbatte in query tipo :
select * from ( select * from blabla union select * from blabla ) as myBlabla

il rischio è che si debba valutare l'apertura di parentesi la chiusura e il breve parser fatto con affetto va a ramengo.

Torna comodo sapere ANCHE SE E' UN TRUCCO VECCHIO e stra VECCHIO, che ogni tanto si può far credere ai
vari "db engine" che stanno facendo qualcosa di utilmente inutile.

SELECT * FROM utenti WHERE 1=1 equivale per esempio a SELECT * FROM utenti.

Certo è vero equivalgono per risultati .. ma in tempi macchina ?? o cicli che dir si voglia ??

Su estrazioni piccole la differenza è minima (1000 rec), su estrazioni grosse(100000 rec) il peso si inizia a notare,
ma la cosa varia da db engine a db engine.

martedì 16 febbraio 2010

Per non perdere il focal point....

In troppi casi, nel nostro lavoro, rischiamo di perdere concentrazione o di allontanarci dalla soluzione. Le cause ? generalmente quisquiglie, rumore, pressione...

Il risultato... classi che fanno la stessa cosa, uno sproposito di righe di codici perfettamente inutili che appesantiscono notevolmente le prestazioni del prodotto finale.

E' possibile ovviare a questo problema ? di metodi ce ne sono tanti e ogniuno ha il suo, e per ogniuno può essere più o meno complesso.

Io mi sono fatto un schema, sul design pattern che più volte mi è tornato utile e più che altro mi serve per ragionare e soffermarmi su quello che sto facendo.

Intent
che cosa fa / o che cosa deve fare ?

Also konw as well
ho già fatto altro o esiste qualcosa di simile ?

Motivation / scenario
Uno scenario / disegno che illustra il problema e come gli oggetti lo risolvano

Applicability
In quali situazioni è applicabile il Design pattern ? Esistono esempi ? Come riconoscere le situazioni.

Structure
una rappresentazione grafica basata sulla notazione Object modelling

Partecipants
Le classi e gli oggetti che partecipano al pattern e le loro responsabilità.

Collaboration
Come le classi e gli oggetti collaborano per conncorrere alle loro responsabilità.

Consequences
Che cosa comporta l utilizzo del pattern in questione, quali sono i limiti e le sue dipendenze.

Implementation
Quali sono i limiti imposti nell'implementazione ?

Sample Code
una porzione di codice che chiarisca come implementare il codice nel linguaggio.

Konow Use
un esempio nel mondo reale del pattern in oggetto

Related Patterns
Ci sono altri pattern che definisco la soluzione? E possibile che questo debba o possa interagire con altri pattern?


Ora non ricordo se questa è una rielaborazione di un qualcosa che avevo trovato sul web tempo fa, ma l'adotto e ritengo che sia parecchio parecchio utile.

lunedì 15 febbraio 2010

Test-Driven ? Yes...

Come per tutte i concetti o paradigmi o metodologie, nell'ambito informatico tutto è astratto e tutto può essere applicato a diversi concetti.

Affrontando soluzioni in D.D.D, emerge subito il concetto di Test-Driven, ma è contestualizzabile solo per il D.D.D. ? Secondo me il concetto è decisamente astratto...

Parafrasando l'esempio banale la realizzazione di una calcolatrice, sia l'analista che il programmatore, daranno per scontato che al primo avvio non si verifichino problemi, poi basta premere una lettera al posto di un numero... e puf ci becchiamo un eccezione...

Questo perchè ? Semplice Troppe volte ci si dimentica di testare tutto il nostro codice... no.
Questo avviene perchè non è chiaro lo scopo di quello che stiamo facendo.

E gli elementi "di base" che il più delle volte diamo per scontati non sono stati presi in considerazione.

Il paradigma del T-D è che si deve testare una funzionalità per volta e che il test deve essere ripetibile e che il test deve essere positivo prima di aver scritto il codice...

Ma davvero ?? Si Tornando alla nostra calcolatrice, se la pressione del bottone 1 deve scatenare
la scrittura del testo 1 nella casella di testo e popolare un buffer, già sappiamo che cosa non dovrà fare il bottone 1...
Interpretando quindi il T-D è utile sapere e implementare il codice affinche la pressione del bottone 1 corrisponda solo a quell'azione...

Detto così forse è anche troppo semplice, ma il concetto di base è questo.

venerdì 12 febbraio 2010

Server-Client-Server

Quando programmare diventa quasi un paradosso...

Siamo sempre nell'ambito web, e in questi giorni mi sto divertendo un sacco con Ajax, devo dire che bisogna pestarci un
po la testa.. ma il risultato può essere sorprendente.

Diciamo pure che questo è l'ennesima evoluzione del controllo AutoCompleteExtender.... di cui ho scritto qualcosa
qualche giorno fa.. (se tutto va bene l'altro ieri).

Il concetto di aiutare l'utente nella composizione di un dato, è cosa buona, è più complessa quando quanto dobbiamo
prelevare è il frutto di una query fatta su una vista con 20 colonne... e strano a dirsi è necessario mostrare tutti i 20
attributi, in un form.

Va da se che se mostro nella lista del AutoCompleteExtender tutti i 20 campi.. anche l'utente più sgamato si ritrova
nel pieno dell'incomprensibilità di ciò che sta leggendo.

Quindi torna utile pubblicare nella lista del AutoCompleteExtender solo lo stretto necessario ... e riportarlo al lato
Client.

Qui mi è sorto un dubbio .. e da qui come ritorno sul server ?? magia ?? Prestidirigilibizzazione ?? no...

patiamo dalla form e da ciò che contiene:

asp:ToolkitScriptManager ID="tsMain" runat="server" EnablePageMethods="True"
/asp:ToolkitScriptManager

asp:TextBox ID="txtrSearch" runat="server" Text=""/asp:TextBox

asp:AutoCompleteExtender ID="AutoCompleteExtenderDemo" runat="server"
TargetControlID="txtrSearch" ServiceMethod="GetCompletionList"
MinimumPrefixLength="1" CompletionInterval="1000"
EnableCaching="true" CompletionSetCount="10" OnClientItemSelected="ItemForSplit"
/asp:AutoCompleteExtender

asp:TextBox ID="txtDemo" runat="server" /asp:TextBox

In più ci servono un paio di cosette nel codeBheind...

[System.Web.Services.WebMethod]
public static string DoMore(string valueText)
{
return "Simple Test";
}

Rimane valida la GetCompletionList ( documentata qualche post fa.. )

[System.Web.Services.WebMethod]
public static string[] GetCompletionList(String prefixText, int count)
{
List suggetions = GetData(prefixText, count);
return suggetions.ToArray();
}

private static List GetSuggestions(string key, int count)
{
List suggestions = new List();

for (int i = 0; i < count; i++)
{
// la vostra logica di estrazione...
}
return suggestions;
}

E nella pagina .. ci servono queste due function ( nel aspx )

function ItemForSplit(source, eventArgs)
{
Value = eventArgs.get_value();
var rs = document.getElementById('txtrSearch');
var dm = document.getElementById('txtDemo');
rs.value = "";
PageMethods.DoMore(Value,OnCallComplete,null,dm);
}

function OnCallComplete(result,txtOutput,methodName)
{
txtOutput.value = result;
}

Questi scrip devono essere MESSI NEL BODY .. e non nella header .. se non no va... by Design...

Che cosa ottenete ???

che il Client richiede al Server i dati la prima volta con GetCompletionList, li usa e richiede per la seconda volta
i nuovi dati al Server...

Funziona che è una meraviglia..

giovedì 11 febbraio 2010

Virtual (mente) parlando...

Consentire l'estensibilità/ereditarietà è sempre "Un bene" ?

Parafrasando l'idea di base "reduce-to-reuse" sono entrambe (estensibilità ed ereditarietà) "Un bene", perchè questo ci consente di scrivere meno codice, di usarlo meglio, di finalizzare lo scopo di una o più classi.

Tuttavia è necessario uno sforzo concreto in fase d'analisi.
Supponiamo che per applicativo venga richiesto di realizzare anagrafiche, attività è qualche funzionalità generica,
da rilasciare nella "Fase 1". Supponiamo quindi che per lo stesso applicativo sia prevista una "Fase 2" dove ogni azione
eseguita sulla anagrafica (insert/update/delete) debba essere scritta in un log.

In un primo momento al Team viene richiesto di implementare solo la "fase 1" e non venga presentata la "fase 2" .

Il team crea una serie di form per l'anagrafica con le azioni richieste che risulteranno non troppo diverse da queste..

protected void btnInsert()
{
// logiche di verifica dei campi...

// Altre logiche di verifica (doppi e/o simili)...

// codice per insert...
}

Dopo una serie di test il Team consegna l'applicativo... e solo dopo la consolidazione di quanto fatto, o l'accettazione
viene proposta al Team la "fase 2"...

In questo preciso caso eritidare i form implica una quasi completa revisione del codice già scritto ... con una conseguente
e onerosa perdita di tempo...

Se si facesse un passo in più... in fase d'analisi comunicando le due Fasi e comunicando che la seconda non è necessaria
subito...

il team potrebbe produrre per la "fase 1" qualcosa di simile a :

protected virtual void btnInsert(object sender, EventArgs e)
{
// logiche di verifica dei campi...

// Altre logiche di verifica (doppi e/o simili)...

// codice per insert...
}

e ( a fronte dell'aver ereditato la base .. )

protected override void btnInsert_Click(object sender, EventArgs e)
{
base.btnInsert_Click(sender, e);

// codice per Log
}

A fronte di un obbiettivo ben definito è possibile prendere delle decisioni che rendano più semplice il
raggiugimento dello stesso, ed in questo caso "semplice" implica anche Meno costoso...

mercoledì 10 febbraio 2010

OnRowDataBound

Le girdview hanno qualche piccola potenzialità nascosta.

Questo evento si scatena subito dopo aver invocato il DataBind() che ricordiamo essere l'associazione fra i dati e la gridview.
L'intercettazione dell' OnRowDataBound consente parecchie attività sfiziose.

L'evento è un GridViewRowEventHandler e i GridViewRowEventArgs sono davvero tanti.


System.Data.DataRowView dataValue = (System.Data.DataRowView)e.Row.DataItem;

if (dataValue != null) // nel caso dell'intestazione è NULL
{
if (dataValue.Row.ItemArray[_VerifyDeleted].ToString().ToLower() == "true")
{
e.Row.CssClass = "rL";
}
}

In questo caso specifico cambio lo stile di una Row se trovo un valore in un campo della dataTable ...

dataValue
(vista o presentazione dei dati) la riga non è ancora stata renderizzata.
dataValue.Row.ItemArray
(dati fisico o record rappresentato come Item Array]
e.Row
(riga che sta per essere renderizzata)

Il mio consiglio è di usare una gridview gestita a pagine ... con un quantitativo di righe più o meno basso.
Nell ordine dei 25 / 30 elementi, questo perchè OnRowDataBound è generato per ogni riga..
va da se che fare IO su 20 elementi ha un costo .. su 100 costa un bel po di più.

In questo evento ha delle buone potenzialità, è in qui che si possono aggiungere controlli e handler sui
controlli (tipo Button + Click, CheckBox ... e via e via) il limite rimane la creatività ed eventuali tempi di Render

martedì 9 febbraio 2010

Consentitemi ...

Clamore e stupore... ancora una volta chi opera le traduzioni merita un PLAUSO...

errore di runtime ASP.NET:
Solo i controlli del contenuto sono consentiti
direttamente in una pagina di contenuto che contiene
controlli del contenuto.

Come mi è capitato ???
Ho aggiunto uno script ad una MASTER PAGE FILE contenente uno script manager..
probabilmente ho messo lo script nel punto "sbagliato"... ma si può dare un messaggio così??

script language ="javascript"

/script
asp:Content ID="cpPrototype" ContentPlaceHolderID="cpHolder" runat="server"
(errore )

asp:Content ID="cpPrototype" ContentPlaceHolderID="cpHolder" runat="server"
script language ="javascript"

/script

tutto ok... mamma mia...

AutoCompleteExtender...

Sembra facile ma non è difficile...
Il nuovo ajax tool kit sembra semplice da usare ma non è sempre chiaro ne l'esempio di Ms, ne l'esito che otteniamo.

Decisamente inatteso è il comportamento dell' AutoComplete, ci sono esempi sparpagliati pseudo casuali, e come sempre
alcuni vanno.. altri no. E' possibile che chi scrive "si fa così" o "vi basta fare così" ( lo faccio anch'io... eh eh ) non documenti
l'ambiente in cui è stato fatto il test.

AjaxControlToolkit ver: 3.0.31106.0
System.Web:2.0.0.0
System.Web.Extensions:3.5.0.0

La vera domanda è perchè tutta sta zozzeria non è allineata ??? c'e' da chiederlo all'installer o a come dover
roccambolescamente installarsi tutto a mano... "fare una cosa fatta bene no ?"

cmq

1) createvi una nuova Web Solution ( non ho provato con il sito web)
2) assicuratevi di mettere...
Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp"
3) nel form..
form id="form1" runat="server"
asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server"
/asp:ToolkitScriptManager

asp:TextBox ID="txtInOrderToComplete" runat="server" Text="" /asp:TextBox
asp:AutoCompleteExtender ID="AutoCompleteExtenderDemo" runat="server"
TargetControlID="txtInOrderToComplete" ServiceMethod="GetCompletionList"
MinimumPrefixLength="1" CompletionInterval="1000"
EnableCaching="true" CompletionSetCount="10"
/asp:AutoCompleteExtender
/form

Nota come al soliti il maggiore e il minore sto blog me li cassa !!

4)nel CodeBehind

[System.Web.Services.WebMethod]
public static string[] GetCompletionList(String prefixText, int count)
{
List suggetions = GetData(prefixText, count);
return suggetions.ToArray();
}


private static List GetSuggestions(string key, int count)
{
List suggestions = new List();

for (int i = 0; i < count; i++)
{
// la vostra logica di estrazione...
}
return suggestions;
}

Tecnicamente parlando non abbiamo implementato un web service per ottenere i dati .. chiaro che la logica
la si può spostare un po dove si vuole .. un po dove più fa comodo...

Ragioniamoci un po sopra...

Perchè statico ???
Perchè se non è statico non funziona.. certo come risposta fa un po acqua, ma sono convinto che la chiamata di un
web services ( o web method ) debba essere statica.

Perchè string[] e non List ???
Perchè il bind sulla lista ( o pseudo lista) che viene creata come output necessita una array di string[]

Perchè (String prefixText, int count) nella firma ???
Perchè la firma proviene dall'oggetto AutoCompleteExtender, e se non corrisponde... non va.

Posso cambiare ServiceMethod="GetCompletionList" ???
ServiceMethod="GetCompletionList" deve corrispondere al
public static string[] GetCompletionList(String prefixText, int count)

Bene questo è il quanto ..

Per altro non è necessario un update panel, ma funziona anche con lui.

buon divertimento.

giovedì 4 febbraio 2010

C:\WINDOWS\system32\ctfmon.exe "Ma che cosa è?"

Parliamo giusto per qualche attimo ... che non fa male.

Qusto eseguibile E' DI MICROSOFT, ma ha un gemello detto anche il virus della "pen Drive" o "Chiavetta".
Più o meno l'abbiamo contratto tutti o se l'abbiamo non lo sappiamo.
Prendete la vostra penna usb infilatela nella vostra presa usb... e sbirciate se vi trovate un autorun.inf....
L'avete trovato, bene ... non troppo, ma bene.. ora apritelo con il NOTEPAD, non eseguitelo, editatelo,
e dentro troverte una zozzeria simile a

[autorun]
shellexecute=Recycled\ctfmon.exe
shell\Open(&0)\command=Recycled\ctfmon.exe
shell=Open(&0)

Come noterete .. "ctfmon.exe" è molto uguale a "ctfmon.exe" ma non sono la stessa cosa...
Il primo è un brillante Trojan il secondo è .. (suspance) un componente aggiuntivo di Office 2003
perfettamente INUTILE ai più.

C:\WINDOWS\system32\ctfmon.exe Questo ragazzaccio serve per l'input alternativo, che può essere
Riconoscimento Scrittura..
Sintesi e riconoscimento vocale..

Come sostengo può essere importante per chi ha dei deficit, ma dato che ms l'installa di default
supponendo che siamo tutti possibili portatori di Deficit... tuttavia non ti dice che lo fa....

La situazione finale è tristemente la seguente...
apri word ne parte uno ( che rimane appeso )
apri excel ne parte un'altro .. ( che strano ma vero rimane appeso )
apri outlook e caso strano (perchè usare uno di quelli appesi ) te ne apre un'altro che fa sempre bene...

Morale se aprite in un giorno 20 documenti vi trovate 20 ctfmon.exe...

Potete fare una cosa semplici crearvi una Restriction POLICY per evitare che parta... m alla fine vi ritrovate
l'event viewer pieno di zozzerie..

Oppure rimuoverlo
per il virus .. la cosa è semplice.. formattate la chiavetta.. e svuotate il cestino del pc e puf non ha persitenza...
Più che altro c'e' da tirarlo giù via Taskmanager...

per l'applicazione ms .... ci vuole un po di più, ma è semplice..
1) teskmanager e tirate giù tutti ctfmon ..
2) pannello di controllo / installazione applicazioni / Microsoft Office 2003
3) Scegliere "Cambia"
4) Aggiungi/Rimuovi caratteristiche
5) Fleggare Personalizzazione avanzata applicazioni
6) da Personalizzazione avanzata Espandere Microsoft Office

a questo punto cercate tutto quello che è inerente alla sintesi per il riconoscimento vocale o per gli input alternativi...
In più vi conviene rimuovere... il traduttore dal francese, dallo spagnolo, dal tedesco e tutte le altre lingue di cui
non avete bisogno ..


7) esegui / regedit
8) rimuovere da HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\ Ctfmon.exe
9) esegui / regsvr32 /u msctf.dll

Fatto abbiamo finito ...


lunedì 1 febbraio 2010

Wrappare che passione...

Dato che mi sarebbe tornato comodo crearmi un piccolo manager di sessione.. mi sono wrappato tutta la session.

Non mi ha dato di volta il cervello.. anche se ai più potrebbe sembrare. Per una questione di comodo mi trovo
a dover condividere quest'oggetto un po qua e un po la in un web application, e dato che non so e non posso
sapere chi o come aggiungerà elementi o chi o come li rimuoverà me la wrappo in toto, e poi mi occuperò di
aggiungere qualche metodo specializzato per la gestione in modo che chi aggiunge o toglie lo faccia come dico
IO !!

caso contrario sono dati "persi" o senza persistenza ..

cmq dato che potrebbe servire..

using System;
using System.Data;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
using System.Web;
using System.Web.SessionState;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace Life20.Commons
{
public class wrSession
{
private HttpSessionState _xSession = null;

#region Public Properties
public int CodePage
{
get { return _xSession.CodePage; }
}

public HttpSessionState Contents
{
get { return _xSession.Contents; }
}

public HttpCookieMode CookieMode
{
get { return _xSession.CookieMode; }
}
public int Count
{
get { return _xSession.Count; }
}

public bool IsCookieless
{
get { return _xSession.IsCookieless; }
}

public bool IsNewSession
{
get { return _xSession.IsNewSession; }
}

public bool IsReadOnly
{
get { return _xSession.IsReadOnly; }
}

public bool IsSynchronized
{
get { return _xSession.IsSynchronized; }
}

public NameObjectCollectionBase.KeysCollection Keys
{
get { return _xSession.Keys; }
}

public int LCID
{
get { return _xSession.LCID; }
}

public SessionStateMode Mode
{
get { return _xSession.Mode; }
}

public string SessionID
{
get { return _xSession.SessionID; }
}

public HttpStaticObjectsCollection StaticObjects
{
get { return _xSession.StaticObjects; }
}

public object SyncRoot
{
get { return _xSession.SyncRoot; }
}

public int Timeout
{
get { return _xSession.Timeout; }
set { _xSession.Timeout = value; }
}
#endregion

#region Builder
public wrSession(HttpSessionState crSession)
{
_xSession = crSession;
}
#endregion

#region Public Methods
public void Add(string _Name, object value )
{
_xSession.Add(_Name, value);
}

public void Abandon()
{
_xSession.Abandon();
}

public void Clear()
{
_xSession.Clear();
}

public void CopyTo(Array array, int index)
{
_xSession.CopyTo(array, index);
}

public override bool Equals(object obj)
{
return _xSession.Equals(obj);
}

public IEnumerator GetEnumerator()
{
return _xSession.GetEnumerator();
}

public override int GetHashCode()
{
return _xSession.GetHashCode();
}

public new Type GetType()
{
return _xSession.GetType();
}

public void Remove(string Name)
{
_xSession.Remove(Name);
}

public void RemoveAll()
{
_xSession.RemoveAll();
}

public void RemoveAt(int index)
{
_xSession.RemoveAt(index);
}

public override string ToString()
{
return _xSession.ToString();
}
#endregion
}
}


questa è la base.. senza naturalmente le mie specializzazioni...