What we actually were trying to achieve is, that we can call a WCF RESTService function doing a PUT action and having multiple (exactly three) input parameter. First goal was having only two input parameter of type URL parameter and the third within the body. (should be like a kind of put that body parameter beneath the entity which is identified by parameter one and two

  • this is how we do the interpretation of a RESTful Service). From the WCF perspective this isn’t such difficult quest:
[WebInvoke(Method = "PUT", UriTemplate = "CreateArchive/IncidentId/{IncidentId}/IncidentTimestamp/{IncidentTimestamp}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
ItemResult<string> CreateArchive(Guid incidentId, DateTime incidentTimestamp, Dictionary<string, byte[]> archiveContent);

On the other end of the wire is an RestSharp client sitting, which actually made this task as simple as on the WCF side.

RestClient client = new RestClient(baseUrl);
RestRequest request = new RestRequest
{
Method = Method.PUT,
Resource = "CreateArchive/IncidentId/{IncidentId}/IncidentTimestamp/{IncidentTimestamp}",
RequestFormat = DataFormat.Json
};
request.AddParameter("IncidentId", incidentId, ParameterType.UrlSegment);
request.AddParameter("IncidentTimestamp", incidentTimestamp.ToString("r"), ParameterType.UrlSegment); request.AddBody(content);
RestResponse<ItemResult<string>> result = client.Execute<ItemResult<string>>(request);

But we figured out some problems resulting from the type we chose for the input parameter. The Dictionary<string, byte[]> instance was always NULL. It took some time to figure out it was always NULL. Reading the MSDN docs carefully shows why: Stand-Alone JSON Serialization contains following paragraph:

Dictionaries are not a way to work directly with JSON. Dictionary<string, object> may not be supported in the same way in WCF as expected from working with other JSON technologies. For example, if “abc” is mapped to “xyz” and “def” is mapped to 42 in a dictionary, the JSON representation is not {“abc”:”xyz”,”def”:42} but is [{“Key”:”abc”,”Value”:”xyz”},{“Key”:”def”,”Value”:42}] instead.

So the cause is that WCF is not compatible to general AJAX/JSON serialization but uses its own Serializer/DeSerializer -> the DataContractJsonSerializer. RestSharp sits on top of the Json.NET library - a general approach to work with JavaScript and JSON formatted data. The incompatibility appears in our case in the Dictionary parameter while the other data types were well serialized and deserialized. The following graphic tries to show the incompatibilities in a more strikingly way.

resrsharp_incompatible

Fortunately RestSharp offers the ISerializer and IDeserializer interfaces to contribute own implementations of adapter supporting special communication protocols (as the WCF datacontractjsonserializer is in this case). So what wie did is implement our own JsonWcfSerializer:

public sealed class JsonWcfSerializer : ISerializer, IDeserializer { }

containing two functions string Serialize(object obj) and T Deserialize<T>(RestResponse response) where T : new() using the datacontractjsonserializer.

public string Serialize(object obj)
{
if (null == obj) throw new ArgumentNullException("obj");
string result;
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
dataContractJsonSerializer.WriteObject(memoryStream, obj);
memoryStream.Seek(0, SeekOrigin.Begin);
using (StreamReader streamReader = new StreamReader(memoryStream))
{
result = streamReader.ReadToEnd(); streamReader.Close();
}
memoryStream.Close();
}
return result;
}
public T Deserialize(RestResponse response) where T : new()
{
if (response == null) throw new ArgumentNullException("response");
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T)); T result;
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(response.Content)))
{
memoryStream.Seek(0, SeekOrigin.Begin);
result = (T)dataContractJsonSerializer.ReadObject(memoryStream);
memoryStream.Close();
}
return result;
}

resrsharp_compatible

So as you can see in the second graphic the adapter turned from orange to gray and is now fitting the WCF communication protocoll.

At least I like to share some configuration parameters with you - in our case we need to send some byte[] with a length larger than the default 64kb (65536 bytes). Beneath the bindings-section of your system.ServiceModel section in the Web.config you need some additonal entries:

Web.config configuration
<webHttpBinding>
<binding name="ArchiveBinding" maxBufferSize="10485760" transferMode="Buffered" bypassProxyOnLocal="false" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" maxReceivedMessageSize="10485760">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</webHttpBinding>

As you can see it consists of two parts - the binding and the readQuotas. The maxBufferSize (maxReceivedMessageSize - which must be of same value as maxBufferSize) controls the amount of data, which could be received by the service. (in our case we estimate a length not bigger than 10MB). As you can guess a byte[] of 10MB has some extraordinary length. Therefore you need the readQuotas to allow the service a deserialization of an array with such length. We set the quotas to Integer32.MaxValue which is the max value allowed

  • as we are in a closed private system.

Hope this helps to send dictionaries to and receive them from your Wcf- Service!