views:

1623

answers:

2

I'm trying to code a web service client in Silverlight for a RESTful WCF service that I have developed. In Silverlight I am constructing the body of the WebRequest using a DataContractSerializer instance.

This approach works great if there is a single argument for the OperationContract. It doesn't work so well if there are multiple arguments defined in the OperationContract. I believe this is because a dynamic type is being created by WCF that is named after the OperationContract and the members of that type are named after the parameters defined for the operation. The purpose of the dynamic type is to ensure that a single XML element exists in the message body being submitted to the WCF service... makes sense. Question is how do I construct this dynamic type myself so that I can submit it to the DataContractSerializer myself.

First example is a working example that defines a single parameter. Second example is the scenario that I am trying to solve (multiple parameters).


Example 1:

[OperationContract,
WebInvoke(Method = HttpMethodType.Post,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate = "UnregisterProvider"),
WebHelp(Comment = "Unregistered the provider type with the specified URI.")]
void UnregisterProvider(RdfUri providerUri);

Code used to serialize message body:

StringBuilder msgBody = new StringBuilder(250);
using (XmlWriter xw = XmlWriter.Create(msgBody))
{
    var serializer = new DataContractSerializer(typeof(RdfUri));
    serializer.WriteObject(xw, providerUri);
}

Resulting body:

<RdfUri xmlns="http://schemas.datacontract.org/2004/07/Intellidimension.Rdf"&gt;esp:semanticserver&lt;/RdfUri&gt;


Example 2:

[OperationContract,
WebInvoke(Method = HttpMethodType.Post,
    BodyStyle = WebMessageBodyStyle.WrappedRequest,  /* WrappedRequest must somehow signal WCF to create the anonymous type as it is required for multiple parameter OperationContracts */
    UriTemplate = "RegisterProvider"),
WebHelp(Comment = "Registered a provider type with the specified URI.")]
void RegisterProvider(PoolableEntityServiceProviderDescriptor descriptor, RdfUri providerUri);

Code used to serialize message body:

//?????

Resulting body:

<RegisterProvider xmlns="http://tempuri.org/"&gt;
  <descriptor i:type="a:SemanticServerProviderDescriptor" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:a="http://schemas.datacontract.org/2004/07/Intellidimension.RdfEntity.Service.DataContracts"&gt;
    <a:ConnectionString>Data Source=.\sqlexpress;Initial Catalog=RdfTest1;Persist Security Info=True;User ID=sa;Password=password</a:ConnectionString>
    <a:ProviderGraphUri>http://entitystore/graph-provider&lt;/a:ProviderGraphUri&gt;
  </descriptor>
  <providerUri>esp:semanticserver</providerUri>
</RegisterProvider>


Update 1:

Here is a guy on the MSDN forums asking a similar question: Can I use DataContractSerializerOperationFormatter to format a list of parameters from client to server?

DataContractSerializerOperationFormatter is an internal class. So looks like I may have to implemented it's behavior for my client.

Update 2:

Some are asking why I am not just using the normal Silverlight WCF client generated by a service reference. The reason is that the WCF service on the server is a RESTful service. From the docs:

No analog to the WebHttpBinding provided in WCF is provided. To access pure HTTP, REST, RSS/Atom, or AJAX services from Silverlight 2, use the techniques described in Accessing HTTP-Based Services Directly, such as the WebClient class. To access ASP.NET AJAX services, see Accessing ASP.NET AJAX Services.

A: 

Let me ask you a question back. Let's say you can get this working. What is the content-type of the POST request body?

You are abusing HTTP by trying to pretend that a POST can send two things. If you want to do what you are doing then why not use regular WCF service contracts. It is easy to send multiple parameters with those.

The problem with System.ServiceModel.Web is that it only 90% decouples the client from WCF. Therefore to get things to really work properly you need WCF on the client side. At which point why not stick with regular WCF service contracts.

If you really want to use HTTP as it was intended, then use a technology that will help instead of hinder.

Darrel Miller
I think this is the second time you have told me to not use WCF :) I find that somewhat amusing. I appreciate your persistence. There are not multiple things getting posted in the POST body though, there is one element which is wrapped and decomposed on the server to multiple method parameters.
spoon16
Also, I am using Silverlight and am using the DataContractSerializer because it's convenient, but I don't see how WCF requires the client to have WCF also in any way. A RESTful WCF endpoint is the same as any other RESTful endpoint. Right?
spoon16
I'm not saying that it is not possible to create a non WCF client that will talk to a WCF service, however you will into many issues. Try posting a stream to a WCF endpoint. Try doing basic auth with a non windows user name. Try returning an error that is not the standard html page.
Darrel Miller
Maybe I just started with it too early. I was using the "REST Starter Kit" when it was called Biztalk services SDK in May 2007. Try controlling the format of a date parameter in a query string. Try supporting URLs with optional segments. My list of problems was endless.
Darrel Miller
Try XML responses with no namespaces. Try returning your own custom media type. For me there was friction at every step of the way.
Darrel Miller
You should post all of these problems as questions on SO :)
spoon16
A: 

What was the reason to not use a WCF client with SilverLight?

John Saunders
it's a RESTful service. Silverlight WCF client doesn't work with a RESTful service, only with SOAP services.
spoon16