venerdì 30 novembre 2007

Come creare un web control contenitore

Nel nostro controllo modifichiamo la fase di render a run-time inserendo un Javascript che emette l'HTML.

protected override void Render(HtmlTextWriter output){
output.Write("");
}


creiamo la classe per il rendering a design-time.

public class DesignTime : ControlDesigner{

ControlloCon FControllo;

public override void Initialize(System.ComponentModel.IComponent component){
this.FControllo = (ControlloCon)component;
base.Initialize(component);
}

public override string GetDesignTimeHtml() {
try{
if (FControllo.Text == string.Empty)
return GetEmptyDesignTimeHtml();
else
return "
" + FControllo.Text + "
";
}
catch(Exception ex){
return GetErrorDesignTimeHtml(ex);
}
}

protected override string GetEmptyDesignTimeHtml(){
return "
" + typeof(ControlloCon) + " " + FControllo.ID + "
";
}

protected override string GetErrorDesignTimeHtml(Exception e){
return CreatePlaceHolderDesignTimeHtml(e.Message);
}
}

Infine associamo il controllo alla classe di DesignTime.

[Designer("ControlloConDesignTime.DesignTime")]
public class ControlloCon: System.Web.UI.WebControls.WebControl{

martedì 27 novembre 2007

Insert nel dataset di VS2005

Usando i typed dataset di VS2005 come data layer si risparmia un sacco di tempo perchè si auto crea tutto uno strato di classi, metodi e query (per SQL: è questo l'ambiente che uso) che possono essere usati dallo strato business sovrastante.

Oggi ho scoperto una cosa alquanto allarmante, almeno fintanto che non lo si sa.

Mi focalizzo sul metodo di insert di una tabella del dataset. Si può sceglere tra text o stored procedure o table direct.
Nel caso si scelga text si può inserire il testo in due modi:
- usando il query builder (cliccando sugli appositi 3 puntini nel campo CommandText delle proprietà);
- inserendo a mano la query (magari facendo un copia/incolla da SQL manager).

C'è però una notevole differenza tra i due metodi: il primo infatti accoda "di soppiatto" un comando di select conforme con il comando di insert appena editato da noi.
Questo select è FONDAMENTALE in quanto serve per riportare i nuovi valori dal database al dataset che, in caso di assenza del select, rimane con i valori vecchi.
Il caso più eclatante si ha quando l'insert interessa delle righe di una tabella che ha un'indice auto-increment: auto-increment sia sul db (con step positivi) sia sul db (con step negativi)*.
In questo caso gli indici delle righe appena INSERITE sul db manterranno l'indice negativo ma cambieranno stato da added a unchanged. Ad un successivo cambio di stato in Modified si genererà una eccezione di mancanza di chiave primaria in fase di UPDATE, in quanto l'adapter farà affidamento sull'indice di riga rimasto negativo e disallineato dal db.



*: sul perchè è utile fare step negativi nel db per indici auto-increment rimando alla documentazione MS.

venerdì 23 novembre 2007

Problemi a design time (Win.NET)

Scenario:
- si sta sviluppando una interfaccia grafica di un form e si ha bisogno di creare un controllo separato da poi utilizzare nel form principale.
- non si ha l'auto increment nel buid.

Una volta aggiunto lo UserControl nel form, capita di trovarsi questo errore a design time :


per risolverlo basta coronare le proprietà pubbliche dello UserControl con il Custom Attribute
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

e il gioco è fatto.
Da quello che ho capito questo attributo dice al designer di non preoccuparsi di serializzare la proprietà e tirare avanti.
Quello che non mi spiego è perchè ha bisogno di serializzare questa proprietà che non è localizzabile e quindi non è esportata nel file di risorse. Forse è una cosa interna al designer.

sabato 18 agosto 2007

Trovato un server CVS

Dopo aver passato un intero pomeriggio a cercare, installare e testare prodotti free per il backup e il CSV, alla fine mi sono imbattuto in questo CSV server (chiamato CSVNT) scaricabile qui.
Per ora posso dire che è un prodotto all'altezza delle aspettative, mi riservo di tornare sull'argomento più avanti per vedere se dopo un uso più intenso il mio parere sarà cambiato.

Contestualmente vi posso dire che Cobian backup 8 pensandolo come il mio gestore di backup non ha passato la prova in quanto ha ancora dei problemi sull'FTP (pru cambiado utente al servizio, dato che quello di base non può accedere a internet) visto che non chiude mai la sessione; un altro problema è la copia su reti LAN senza dominio: non riesco a dargli il diritto di scrivere sulla directory di destinazione (non escludo che questo sia un problema sistemistico).

mercoledì 15 agosto 2007

Ho scoperto una cosa interessante in Windows.
Tra i settaggi dei Local Security Settings ce ne è uno che recita:
"Network access: Sharing and security model for local accounts".
Se si lascia la selezione: "Classic" si avranno a disposizione per tutte le cartelle la possibilità di definire le autenticazioni in maniera "precisa" (per ogni utente si possono definire le solite autorizzazioni); se si cambia in "Guest only" cambia tutto e l'autorizzazione si semplifica in stile "MS Win Home".

lunedì 6 agosto 2007

Serializzazione di oggetti in C#

Ecco il metodo più semplice per serializzare e deserializzare in un array di byte una istanza di una classe:
public Object Desierializza(Byte[] bytes)
{
System.IO.Stream s = new System.IO.MemoryStream(statistic.DbParameter);
s.Write(bytes, 0, bytes.Length);
BinaryFormatter bf = new BinaryFormatter();
return bf.Deserialize(s);
}

public Byte[] Serializza(Object o)
{
System.IO.Stream s = new System.IO.MemoryStream(statistic.DbParameter);
BinaryFormatter bf = new BinaryFormatter();
return bf.Serialize(s, o);
}

venerdì 1 giugno 2007

Riflessioni sul calcolo delle tasse sullo scontrino.

Come si calcolano le tasse sullo scontrino in Italia? E nel resto del mondo?

Ecco che spiego tecnicamente il problema.
Pensiamo ad uno scontrino della spesa: sarà composto da una serie di items contraddistinti dal loro prezzo insieme ad un'array di percentuali di tasse da applicare (no, non ne basta una). Se si volesse internazionalizzare il problema si dovrebbe anche specificare se il prezzo è al lordo o al netto delle tasse, visto che qui da noi al dettaglio sono espresse al lordo, mente in USA sono sempre al netto.
Volendo essere ancora più generici si potrebbe pensare che ogni singolo prezzo può essere espresso diversamente: un po' netti e un po' lordi, ma per ora questa ipotesi la facciamo cadere.

In uscita vorrò avere il totale netto, il totale lordo, e il totale delle tasse della spesa.
In aggiunta vorrei sapere per ogni item quant'è la il lordo, il netto e le tasse a prescindere dalla definizione del prezzo (cioè se è definito come lordo o come netto: è ovvio che comunque uno dei due totali l'ho già).

Ho in mente due metodi per risolvere questo problema.

Il primo metodo prevede di calcolare le tasse per ogni singolo item e poi fare la somma di tutti i netti, di tutte le tasse e di tutti i lordi.
Così facendo l'approssimazione (ad oggi testata solo alla seconda cifra decimale) viene introdotta per il calcolo della tassa di ogni singolo item.

Il secondo metodo prevede che si calcolino i sub totali (lordi o netti) dei prezzi raggruppati per percentuale di tassa.
Su questi subtotali si calcola l'importo delle tasse (un importo per ogni % di tassa) - qui si inserirà l'arrotondamento - e di conseguenza l'importo lordo(se si aveva il netto) o il netto (se si aveva il lordo) e poi si sommeranno insieme tutti i netti, tutti i lordi e tutte le tasse.
In questo secondo metodo, a differenza del primo, non ho tasse per ogni singolo item ma solo sui totali parziali e finali.
Quindi come faccio a sapere quante tasse pago per singolo item?
Un metodo, che è quello che voglio implementare, è quello di ripartire indietro proporzionalmente le tasse sui vari items, introducendo un'altra approssimazione, così che la somma delle tasse ripartite potrà non essere pari alla tassa totale di partenza!!
Commenti?

venerdì 25 maggio 2007

.NET remoting ed eventi

E' da un po' che mi scontro con il problema sintetizzato in oggetto: come sottoscrivere un evento tra due istanze che vivono in due appDomain differenti.
Il meccanismo base non è doverso da una sottoscrizione "normale" tra due istanze che vivono nello stesso appDomain, ma c'è un elemento chiave che DEVE rimanere in testa (ed è quello che invece non mi rimane in testa al momento opportuno): il Garbage Collector NON tiene conto (non riesce credo..) dei "link" via remote.
Poniamo quindi di avere un appDomain1 con una istanza1 e un appDomain2 con una istanza2.
i due appDomain sono ovviamente raggiungibili via remoting.
L'istanza1 crea un delegate ad un proprio metodo e lo sottoscrive ad un evento dell'istanza2.
private void Subscribe()
{
istanza2.RemoteEvent += new EventhHandler(mio_metodo);
}
Come si può vedere l'istanza1 non tiene traccia del delegate che viene creato all'interno del metodo.
Il GC nota che non c'è nessun link a tale delegate e quindi lo rimuove.
Il risultato di tutto questo è che l'istanza1 riceverà notifica dell'evento dall' istanza2 fintanto che il GC non scatta nell'appDomain1. Dopo di che nell'istanza2, all'atto di lanciare l'evento si genererà una eccezzione del tipo "SocketException".

La soluzione è semplice: basta mantere il delegate in memoria nella istanza1, come nell'esempio sotto, e il GC non ce lo cancellerà:

private EventHandler delegate1;
private void Subscribe()
{
delegate1 =
EventhHandler(mio_metodo);
istanza2.RemoteEvent += delegate1
}

Per evitare malintesi voglio sottolineare che questo metodo non è legato in alcun modo al metodo InitializeLifetimeService() da overridare.
QUesto metodo deve essere sovrascritto nelle classi che derivano da MarhalByRefObject facendo in modo che restituisca null se si vuole che il il tempo che tale classe rimarrà attiva in remoto sia infinito, ci.
Un tipico override è:

public override object InitializeLifetimeService()
{
return null;
}

lunedì 21 maggio 2007

Struttura base di una applicazione

Visto che è il mio primo post (sencondo in realtà ma il primo era solo di test) metto le mani ben avanti premettendo che non sono un esperto (sono uno di quelli che gli inglesi chiamano "wannabes") ma che da sempre mi sono sforzato per cercare di capire quale fosse la progettazione migliore per una applicazione generica. Con il termine "generica" voglio comprendere sia le win applications (ovvero che sono pensate e realizzate per girare un una macchina) che le web applications da accedere dal web, comprendendo anche tutte le sfumature intermedie.
La mia idea che si è formata nel tempo è alla fine molto semplice: alla base di tutto ci deve essere una buona struttura a livelli (la famosa struttura ISO/OSI non avevano sbagliato).
Una prima macro suddivisione è a tre livelli:
- La parte di interfaccia;
- la parte di "intelligenza" (business);
- la parte dei dati.

La cosa fondamentale è che ogni layer abbia una sula macro funzione specifica.

Questo potrebbe essere la descrizione verticale della nostra architettura; per fare in modo che il progretto sia realizzato bene e che non vi siano ripetizioni di codice (da evitare come la peste), bisogna individurare delle suddivisioni "logiche" del nostro codice.

Per fare ciò si deve giocare sia con la creazione di librerie che raggruppano tutta una serie di funzionalità e con i midificatori di visibilità che ogni linguaggio evoluto mette a disposizione (public/private/ etc.) con l'aggiunta di un itelligente uso della clausola static.

Questi sono le mie prime generice e superficiali considerazioni sull'argomento.
Visto che non mi considero mai arrivato, sono in costante ricerca di articoli che possano confermare, migliorare o smentire queste mie idee.
Ogni suggerimento / commeto è ben accetto.


sabato 19 maggio 2007

Primo post

Questo é il primo post. Da qualche parte si dovrà pure cominciare.