tags:

views:

774

answers:

3

Setting up a WCF service that uses the webHttpBinding... I can return complex types from the method as XML ok. How do I take in a complex type as a parameter?

[ServiceContract(Name = "TestService", Namespace = "http://www.test.com/2009/11")]
public interface ITestService
{
    [OperationContract]
    [WebInvoke(Method = "POST", 
               BodyStyle = WebMessageBodyStyle.Bare, 
               UriTemplate = "/Person/{customerAccountNumber}, {userName}, {password}, {PersonCriteria}")]
    Person SubmitPersonCriteria(string customerAccountNumber, 
                                string userName, 
                                string password, 
                                PersonCriteria details);
}

Since the UriTemplate only allows strings, what's the best practice? The idea is the client app will post a request to the service like search criteria for a person. The service will respond with the appropriate object containing the data as XML.

A: 

You would think this could be done using UriTemplate, but as of 3.5 WCF does not support this.

RandomNoob
Yeah that was my initial approach... but that was a dead end. What alternatives are available?
Excelsior
+1  A: 

You can post complex types using rest.

[ServiceContract]
public interface ICustomerSpecialOrderService
{    
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "deletecso/")]
    bool DeleteCustomerOrder(CustomerSpecialOrder orderToDelete);
}

The implementation looks like this:

public bool DeleteCustomerOrder(CustomerSpecialOrder orderToDelete)
{
    // Do something to delete the order here.
}

You can call a method from a WPF client:

public void DeleteMyOrder(CustomerSpecialOrder toDelete)
{
    Uri address = new Uri(your_uri_here);
    var factory = new WebChannelFactory<ICustomerSpecialOrderService>(address);
    var webHttpBinding = factory.Endpoint.Binding as WebHttpBinding;
    ICustomerSpecialOrderService service = factory.CreateChannel();
    service.DeleteCustomerOrder(toDelete);
}

Or you can call it with a HttpWebRequest as well, writing the complex type to a byte array which we do from a mobile client.

private HttpWebRequest DoInvokeRequest<T>(string uri, string method, T requestBody)
{
    string destinationUrl = _baseUrl + uri;
    var invokeRequest = WebRequest.Create(destinationUrl) as HttpWebRequest;
    if (invokeRequest == null)
        return null;

    // method = "POST" for complex types
    invokeRequest.Method = method;
    invokeRequest.ContentType = "text/xml";

    byte[] requestBodyBytes = ToByteArray(requestBody);
    invokeRequest.ContentLength = requestBodyBytes.Length;


    using (Stream postStream = invokeRequest.GetRequestStream())
        postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);

    invokeRequest.Timeout = 60000;

    return invokeRequest;
}
Brett Bim
http://blog.hackedbrain.com/archive/2007/10/05/6124.aspx -- ?
RandomNoob
Both your links are broken in your post so I'm not sure I can completely tell what you're doing. Are you saying you can't post complex types using REST?
Brett Bim
How does the complex type get posted using Rest? In the bool DeleteCustomerOrder method, when the post is submitted how does the service get the CustomerSpecialOrder object passed in?
Excelsior
Both my links work, yes that is what I am saying -->parameters<-- cannot be a complex/custom data contract type.
RandomNoob
Well, I'm working on a project right now where we pass complex types to RESTful services using WebInvoke and POST. We have a service that implements the OperationContract above and we call it using WPF clients and mobile clients who post using an HttpWebRequest.I agree with Scott Seely in response to your second link. Complex types get posted and URIs are used to pass simple strings.
Brett Bim
A: 

Your options:

  1. use POST and accept an XML doc of arbitrary complexity, or
  2. use GET and figure a way to map a URL path to your query criterion.

I'd recommend the former, it feels more RESTful and less hacky. The POST would be to submit a query, and in response you'd get a queryId, something relating to what you've submitted.

According to REST ideas, you can then to a get on that ID to get the results of the query.

Cheeso