Thanks Paul,
I don't disagree that a MobileDictionary would be nice. But for what is effectively version 1 we were focused on getting CSLA working, so we only created serializable base types for things required directly by CSLA.
This whole serialization thing is less than ideal, but is really unavoidable. Silverlight simply doesn't have what is required to make something like the BinaryFormatter or NDCS, so MobileFormatter is our answer. Sadly, implementing IMobileObject, especially for lists or dictionaries, is non-trivial.
I was working with a limited time/budget and so we had to prioritize our efforts around what was necessary to get the framework itself functioning - realizing that in future versions there's the need for continual expansion of types.
MobileFormatter will require that both the key and value
implement IMobileObject. So I suppose it can be done by creating the type with
a constraint on both generic parameters to require them to implement that interface.
The only real trick is that ContextDictionary has (I think) a
bit of code to deal with the key value, since we know it is string, and that
code would need to change to somehow serialize the key values and put them into
the serialized byte stream. Pretty much the same as the code for the values now
– but in a way such that the keys and values can be matched up on
deserialiation.
Rocky
From: paupdb
[mailto:cslanet@lhotka.net]
Sent: Sunday, December 07, 2008 4:29 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] CSLA for Silverlight: Inconsistency with
ContextDictionary key type
Fair enough Rocky.
I was thinking it would be as easy as copying the ContextDictionary, renaming
it to MobileDictionary and changing the key type to object in the Silverlight
implementation.
From your reply this would not seem to be the case.
Consider MobileDictionary a feature request for a future version then :)
Although I might have a crack at implementing a MobileDictionary myself - if I have
some success I'll contribute it to Csla if you like.
Thanks for doing that work, that is very helpful!!
I've added this to the wish list (http://www.lhotka.net/cslabugs/edit_bug.aspx?id=252) and it will probably go into 3.6.1.
3.6.0 is feature locked at this point, as I hope for final release on 12/15 - so only show-stopping bugs (and lots of XML commenting) are happening between now and RTW :)
Thank you, this looks quite good.
I will absolutely consider this for 3.6.1, as a high priority,
because it is obviously useful.
As I think I said previously – 3.6.0 is feature-locked and
only critical bug fixes are going in now in anticipation of release.
Rocky
From: paupdb
[mailto:cslanet@lhotka.net]
Sent: Monday, December 08, 2008 7:10 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: CSLA for Silverlight: Inconsistency with
ContextDictionary key type
Hi Rocky
I've put together a basic MobileDictionary and my initial testing seems to
indicate that it works OK with the following combinations:
primitive key + IMobileObject value
primitive key + primitive value
IMobileObject key + IMobileObject value
IMobileObject key + primitive value
I haven't yet tightened up the generic parameters because I thought that might
exclude primitives from being used - correct me if I'm wrong on that
count. I also had the server side match the Silverlight side in terms of
inheriting from Dictionary<>. This means that the same source code
is used on both sides through the VS add as link feature instead of seperate
implementations.
To keep the relationship between key and value I used a simply incremental
counter concatenated to two constant string values to define the serialisation
keys for the dictionary key and dictionary value. Then some simply linq
enabled me to query the serialised inf o values when during deserialisation.
Anyhow its a rough cut but it does work - let me know what you think.
using System.Collections.Generic;
using System.Linq;
using Csla.Serialization;
using Csla.Serialization.Mobile;
using System;
[Serializable()]
public class MobileDictionary : Dictionary<object, object>,
IMobileObject
{
#region IMobileObject Members
private const string keyTxt = "MobDictKey";
private const string valueTxt = "MobDictValue";
void IMobileObject.GetState(SerializationInfo info)
{
int count = 0;
foreach (var key in this.Keys) {
if (!(key is IMobileObject))
info.AddValue(keyTxt +
count, key);
&n bsp; object value = this[key];
if (!(value is IMobileObject))
info.AddValue(valueTxt +
count, value);
count++;
}
}
void IMobileObject.GetChildren(SerializationInfo info,
MobileFormatter formatter)
{
int count = 0;
foreach (var key in this.Keys) {
IMobileObject mobilekey = key as
IMobileObject;
if (mobilekey != null) {
SerializationInfo si =
formatter.SerializeObject(mobilekey);
info.AddChild(keyTxt +
count, si.ReferenceId);
}
object value = this[key];
IMobileObject mobile = value as
IMobileObject;
if (mobile != null) {
SerializationInfo si =
formatter.SerializeObject(mobile);
info.AddChild(valueTxt +
count, si.ReferenceId);
}
count++;
}
}
void IMobileObject.SetState(SerializationInfo info)
{
// Find the MobileDictionary keys
var mobileKeyList = from key in info.Values.Keys
;
where key.StartsWith(keyTxt)
select key.Substring(keyTxt.Length);
foreach (string keyCounter in mobileKeyList) {
object value = null;
// Look for a non-MobileObject base
field value
if (info.Values.ContainsKey(valueTxt
+ keyCounter))
value =
info.Values[valueTxt + keyCounter].Value;
Add(info.Values[keyTxt +
keyCounter].Value, value);
}
}
void IMobileObject.SetChildren(Serializatio nInfo info,
MobileFormatter formatter)
{
// Find MobileDictionary keys
var mobileKeyList = from key in
info.Children.Keys
where key.StartsWith(keyTxt)
select key.Substring(keyTxt.Length);
foreach (string keyCounter in mobileKeyList) {
object value = null;
// Look in the MobileObject children
for a value
if
(info.Children.ContainsKey(valueTxt + keyCounter))
; value =
formatter.GetObject(info.Children[valueTxt + keyCounter].ReferenceId);
// Else look in the non-MobileObject
base fields for a value
else if
(info.Values.ContainsKey(valueTxt + keyCounter))
value =
info.Values[valueTxt + keyCounter].Value;
object key =
formatter.GetObject(info.Children[keyTxt + keyCounter].ReferenceId);
this.Add(key, value);
}
// Attempt to find non-MobileObject keys for
MobileObject values which do not have MobileObject keys
var mobileValueList = from
value in info.Children.Keys
; where
value.StartsWith(valueTxt) &&
!mobileKeyList.Contains(keyTxt + valueTxt.Substring(valueTxt.Length))
select value.Substring(valueTxt.Length);
foreach (string valueCounter in mobileValueList)
{
if
(this.ContainsKey(info.Values[keyTxt + valueCounter].Value))
this[info.Values[keyTxt
+ valueCounter].Value] = formatter.GetObject(info.Children[valueTxt +
valueCounter].Reference Id);
}
}
#endregion
}
Copyright (c) Marimer LLC