My solution will run on dotNET and Mono in a variety of mixes. Connecting the pieces of the Service Oriented Architecture design using WCF. Testing some setups showed me
another difference between dotNET and Mono. The returntype of an operation is Generic Dictionary with a string and a custom type. Would we have used standard System types this would not have been a problem.
I’ll demonstrate this by using a small service that returns authors and books. See code below. The client will receive the information and display the number of items in the result (and some other details). Implementation in the sample project at the end of my post.
[ServiceContract(Namespace = "http://my.solution/2012/04")] public interface IBookService { [OperationContract] Dictionary<string, BookData> GetOneBookPerAuthor(); } [DataContract(Namespace = "http://my.solution/2012/04")] public class BookData { [DataMember] public string Title { get; set; } [DataMember] public int Id { get; set; } }
Depending on the framework (dotNET or Mono) the results differ:
Service | Client | Result |
.NET | .NET | 2 items |
.NET | Mono | 2 items |
Mono | Mono | 2 items |
Mono | .NET | 0 items |
The problem is in the serialization of datacontracts. Where Mono uses the same name as the class for the intermediate type: KeyValueOfstringBookData the dotNET framework does it a little different: KeyValueOfstringBookData6LZ3tCpf (notice the weird stuff at the end). This post on mono-for-android forum of Ximian shed some light.
My solution is to alter the message before it is send to the client when the service is hosted in Mono. For this I’ll use the IDispatchMessageInspector from WCF. In the BeforeSendReply method the KeyValueOfStringBookData tag is replaced with KeyValueOfstringBookData6LZ3tCpf.
public void BeforeSendReply(ref Message message, object instance) { // get the message body var bodyReader = message.GetReaderAtBodyContents(); bodyReader.Read(); // replace to get the weird characters needed for dotNET clients var msg = bodyReader.ReadOuterXml().Replace("KeyValueOfstringBookData>", "KeyValueOfstringBookData6LZ3tCpf>"); // construct the new message var stringreader = new StringReader(msg); var xmlreader = XmlReader.Create(stringreader); var xmldictionaryreader = XmlDictionaryReader.CreateDictionaryReader(xmlreader); var replacedMessage = Message.CreateMessage(message.Version, null, xmldictionaryreader); replacedMessage.Headers.CopyHeadersFrom(message.Headers); replacedMessage.Properties.CopyProperties(message.Properties); // set the new message as THE message message = replacedMessage; }
To find the weird characters for your implementation, host the service in dotNET and request the WSDL. You’ll propably need to dig a little deeper by requesting the ?xsd=xsd0-9 stuff but the information is there