Showing posts with label Serialization. Show all posts
Showing posts with label Serialization. Show all posts

Wednesday, March 25, 2009

Adventures while building a Silverlight Enterprise application part #10

Yeah! It's part 10 of my Adventure series. Sorry, I'm not giving a party or anything, but it feels like a milestone to me.

In this episode we are going to look at an issue I ran into with WCF and Silverlight 2 when using a specific structure in the datacontract. In our case, we wanted to use a Dictionary that would contain another Dictionary as the value. Have a look at our data contract to have a clearer picture:


[DataContract]
[KnownType(typeof(Dictionary<string, object>))]
public class CompositeType
{
private Dictionary<string, object> _properties;
private string _stringValue = "Hello ";

public CompositeType()
{
_properties = new Dictionary<string, object>();
}

[DataMember]
public string StringValue
{
get { return _stringValue; }
set { _stringValue = value; }
}

[DataMember]
public Dictionary<string, object> Properties
{
get
{
return _properties;
}
}
}

As you can see, the dictionary type is a part of our DataContract, trough the use of the DataMember attribute. We also added that same type to our known types list, trough the use of the KnownTypes attribute. We could have used the ServiceKnownTypeAttribute on our interface type as well, with the same result.

If we would now use a Silverlight 2 client with a service reference to this service and make a call to our service, everything seems fine...

...until, that is, we use a Dictionary instance as a value in the Properties property.
In that case an exception occurs, stating:

There was an error while trying to deserialize parameter http://tempuri.org/:GetDataUsingDataContractResult. The InnerException message was 'Error in line 1 position 584. Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data of the 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfKeyValueOfstringanyType' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'ArrayOfKeyValueOfstringanyType' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

If we wouldn't have added the dictionary type to our known types list, the service call would have timed out, without a proper exception, indicating that some problem would have occurred in the service.

I've been digging to see if I could come up with a solution. Googling the exception I got plenty of examples with derived types, but non with nested types and late binding, like I'm using. After some reading on datacontracts and digging into the reference code in the client, I figured that known types in the service might just not be distributed to the client. To prove my theory I started looking at the generated service client instance at runtime. I looked in the EndPoint property which contains the contract, which in turn contains the operations for the contract. As known types are usually scoped at the operations level, I checked to see if it contained any items in the KnownTypes property and in fact it didn't. This means my theory is correct and I should add the dictionary type to the known types list of the operation. As I didn't want to do this in generated code, I decided to do it at runtime:


private Service1Client GetServiceClient()
{
Service1Client client = new Service1Client();

foreach (var operation in client.Endpoint.Contract.Operations)
{
operation.KnownTypes.Add(typeof(Dictionary<string, object>));
}

return client;
}


If I now run the client, everything runs like a charm. What we actually did, by adding these known types, is telling the DataContractSerializer to include our dictionary type when deserializing any incoming xml messages.

You can download some sample code here:


I hope this helps any of you encountering the same issue. If you have any questions or comments, please leave me a comment below.

Tuesday, January 6, 2009

Troubleshooting Silverlight Isolated Storage

Today I ran into this bug in the software I'm working on. I was building a log on mechanism, that would persist a users security token to Isolated Storage. I wanted to do this, because it would enable the application to automatically log on if a valid token was still available.

I actually had this whole thing working last week, but I changed some code on the server end of things and wanted to test my sliding expiration code. So I tested the above functionality only to find out my token was no longer persisted. After extensive debugging, including writing code to watch any changes on the folder holding the Isolated Storage, I came up with nothing.

Getting frustrated, I started searching the Silverlight.net forums for anything on Isolated Storage, to see if anyone had similar issues. I then ran into a post mentioning the Save method on the IsolatedStorageSettings class. I wasn't aware of this method and reading the post, I found out I wasn't the only one. It is not actually mentioned in the video on this topic either.

It is understandable as Save is called automatically whenever a Silverlight application ends, persisting the settings just in time and giving optimal performance, however...
...if, for some reason, an exception occurs while persisting the settings, this results in the settings not being persisted. And that's not the worst. You will NOT notice it, as you will not see the exception.

In my case, I was stupid enough to make one of the classes I use to store information internal, instead of public (as it was before), breaking the serialization of this class. I didn't get any exceptions, until I started calling IsolatedStorageSettings.Save() from code.

My conclusion from all this? Call the save method at some point in your application. It can save you a lot of headaches.

Please leave any comments, questions, remarks below. I'm allways happy to read them and reply.

Friday, November 21, 2008

Exception causes Xml Error in deserialization

This week I seem to run into quite a few nooks and crannies in the .NET framework that put me in front of some tricky issues. This time it had to do with deserialization, or so Visual Studio led me to believe.

Here is the situation. Last week I wrote some code that deserialized an xml file into an elaborate object model. Part of that code was to parse an xsd file and add some objects to the model from there. This all worked well for the past week, as proven by the unittests.

Yesterday I started writing some code to dynamicly load assemblies and classes based on some information from the xsd file. I didn't get to finish it, but as I started working on it this morning, all of a sudden it threw an exception on the deserialization code, stating that I had some error in my xml file. I checked my xml file, which I knew I hadn't changed, and off course it was fine.

So I figured that since the last change I made was in some code that parsed part of the xsd file, I would debug there. As it appeared, the exception occurred whenever I passed a certain XPathNavigator instance into a method of my Factory class for creating a plugin. My first tought was that this occurred because I passed the XPathNavigator to another method. I started to program around this approach, but to no avail.

I crunched my head on it for another half hour until I had to leave for a meeting, but as I came back and looked at my code I realized I actually called the initializer method of a Factory class that I use to load some pluggable classes. I started debugging this method and presto, it raised an exception, because of some small oversight. I fixed this exception and the deserializer code worked again.

Conclusion on this is that some code in the XmlSerializer or it's base classes, catches any exception thrown and re throws another exception which is not related to the actual problem. Fortunately, the inner exception does contain the actual exception, meaning I could have saved myself a lot of time and headaches, by simple looking an the inner exception.

Another thing I learned was that using a singleton pattern to create your factory class is a good thing, but you must pay some attention when debugging.

Wednesday, November 12, 2008

Using XmlSerializer to serialize type information

During the development of a project I'm currently working on, I ran into this. One property of a class I defined is called SimpleType and it holds a Type object. It contains some basic type like int or string.
Part of the project is to store this information and have it easily configurable, so my first thought was to use the XmlSerializer class to simply serialize the objects inside a collection to an xml file. So I wrote some code to do this:


XmlWriter writer = XmlWriter.Create(@"c:\temp\template.xml");
XmlSerializer serializer = new XmlSerializer(typeof(Template));
serializer.Serialize(writer, template);
writer.Close();


Running this code threw a nice exception: "The type System.Int32 cannot be used in this context". At first I was stunned. I didn't have any properties that even related to int. Then I figured it must be the SimpleType property and I needed some kind of workaround for this behaviour.
Here is the code of the property I tried to serialize:


public Type SimpleType { get; set; }


To make it work I started by adding an XmlIgnore attribute to the SimpleType property. This obviously prevents the serializer from including it into the xml file and stops the error from occurring, but now I had no type information in my xml file and I did need it.
So I added a private field to store the type in and added a second property called SimpleTypeName of type string.
The getter of this property simply returns the SimpleTypes Name property. The setter uses the static Type.GetType method to translate a typename into a Type object and sets it in the field.
Here is the code after I rewrote it:


private Type _simpleType;

[XmlIgnore()]
public Type SimpleType
{
get
{
return _simpleType;
}
set
{
_simpleType = value;
}
}

public string SimpleTypeName
{
get
{
if (_simpleType != null)
{
return _simpleType.Name;
}
else
{
return string.Empty;
}
}
set
{
_simpleType = Type.GetType(value);
}
}


To make this work you obviously need the namespace System.Xml.Serialization.

If you have any questions or remarks, please feel free to comment below.