Click here for English Translation
Come promesso ecco il codice di esempio relativo il Workaround del bug segnalato nei giorni scorsi. Innanzitutto occorre dire che, nonostante Microsoft sul Product Feedback Center continui a segnalare che non riesce riprodurre il comportamento, il bug è presente. Il problema probabilmente deriva dal fatto che la formattazione InvariantCulture è sostanzialmente analoga a quella es-US perciò il codice postato va in errore nelle culture diverse ma funziona perfettamente negli U.S.A.
Veniamo ora brevemente a descrivere il metodo utilizzato per aggirare il problema: il concetto si basa sull'utilizzo dell'evento updating della datasource e sull'osservazione che il bug segnalato si presenta esclusivamente quando nella datasource viene specificato l'attributo DataObjectTypeName. In questo caso solamente infatti la datasource tenta di creare una istanza del tipo specificato e di mappare i dati ricevuti dal controllo su questo oggetto, causando così il verificarsi dell'errore. Non specificando questo parametro però sostanzialmente si vanfica l'uso della ObjectDataSource perchè il metodo utilizzato per l'update riceverà tutti i campi separatamente anzichè una istanza dell'oggetto. E' del tutto evidente che è sicuramente possibile effettuare manualmente la mappatura di tutti i parametri ricevuti dal metodo sulla classe richiesta, tuttavia è altrettanto evidente che così facendo ci si espone ad un degrado della manutenibilità del codice in quanto ad esempio aggiungendo una proprietà alla classe target saremmo costretti ad intervenire nei metodi che effettuano la mappatura.
La mia tecnica invece si propone di ripristinare per quanto possibile il normale flusso di lavoro della datasource, intervenendo subito prima della chiamata del metodo update per effettuare la mappatura in modo generalizzato per ogni tipo di oggetto di destinazione. La tecnica comporta che si debbano prelevare i dati provenienti dal runtime nella proprietà InputParameters, mapparli sulla classe richiesta ed in seguito rimuovere tutti i parametri da questa collection ed aggiungervi invece l'oggetto mappato; ecco uno spezzone di codice:
///
/// Handle Updating event of ObjectDataSource
///
/// ObjectDataSource
/// event arguments
protected void Source_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
// instantiate utility class for property mapping
DictionaryMapper mapper = new DictionaryMapper();
// create target object running mapper
Employee employee = mapper.MapDictionary(e.InputParameters);
// clear input parameters
e.InputParameters.Clear();
// add the result object
e.InputParameters.Add("item", employee);
}
A questo scopo ho creato una classe, la DictionaryMapper che essendo appunto generica consente di mappare qualunque le proprietà su qualunque tipo di destinazione. La classe DictionaryMapper i buona sostanza utilizza la reflection per settare le proprietà dell'oggetto destinazione ed applica qualora serva un metodo di conversione corretto, basato su CultureInfo.CurrentUICulture:
///
/// Perform conversion of the given string to the required type
///
/// value to convert
/// typer to convert to
/// converted value
private object ConvertFromString(string value, Type targetType)
{
if (!(value is string))
return value;
// create the converter
TypeConverter converter =
TypeDescriptor.GetConverter(targetType);
// if value contains something
if (value != null)
// convert string to target type using not InvariantCulture
return converter.ConvertFromString(
null,
CultureInfo.CurrentUICulture,
(string)value);
// create an empty instance of target type
return converter.CreateInstance(null);
}
Il processo di conversione utilizzato è analogo a quello che utilizza la ObjectDataSource, ma invece che invocare il metodo convertFromInvariantString() si fa uso di ConvertFromString() passando appunto il valore della Cultura corrente. Nel web.config del progetto che fa da Proof-of-concept ho forzato la cultura italiana in modo tale che l'errore si presenti ovunque.
Download: CultureBug_workaround.zip (4427 Bytes)
powered by IMHO 1.3