Home » .Net FrameworkRSS

Adding querystring parameters to a WCF service operation that accepts Stream

Is there any way to configure a webHttpBinding WCF service to accept multiple querystring arguments, with a Stream argument being the body of the request?

I'd like to do this without omitting the querystring arguments from the operation signature and accessing them from the OperationContext directly.

UriTemplate seemed like the obvious choice, but that only results in AddressFilter mismatch exceptions being thrown.

Moving the arguments to a MessageContract wtih MessageHeader attributes on all non-Stream fields, in order to avoid the "Stream can be the only argument" error, causes an error that MessageHeader attributes aren't supported with webHttpBinding.

Leaving only the Stream argument on the MessageContract informs me that Streams aren't supported in MessageContracts for WebScriptEnablingBehavior anyway.

Any thoughts?

 

9 Answers Found

 

Answer 1

MessageContracts are for SOAP messages as they allow you to specify SOAP headers. The following works for me:

class Program
  {
    staticvoid Main(string[] args)
    {
      WebServiceHost host = new WebServiceHost(typeof(PingService), new Uri("http://localhost:9000/ping/"));

      host.Open();

      Console.WriteLine("Service Ready ...");
      Console.ReadLine();
    }
  }

  [ServiceContract]
  interface IPing
  {
    [OperationContract]
    [WebInvoke(Method="POST", UriTemplate="stuff?n={name}&q={quantity}")]
    void AddStuff(string name, string quantity, Stream data);
  }

  class PingService : IPing
  {
    publicvoid AddStuff(string name, string quantity, Stream data)
    {
      Console.WriteLine("{0} : {1}", name, quantity);
      Console.WriteLine("Data ...");
      using (StreamReader sr = new StreamReader(data))
      {
        Console.WriteLine(sr.ReadToEnd());
      }
    }
  }

And the client is as follows:

staticvoid Main(string[] args)
    {
      WebRequest req = WebRequest.Create("http://localhost:9000/ping/stuff?n=rich&q=20");
      req.Method = "POST";
      req.ContentType = "text/html";
      using (StreamWriter sw = new StreamWriter(req.GetRequestStream()))
      {
        sw.WriteLine("<html><body><h1>Hello</h1></body></html>");
      }

      req.GetResponse();
    }

 

Answer 2

Thanks Richard. I swear I tried just that; could you paste in your service config?
 

Answer 3

If I run a similar, though web application based, configuration (configured with webHttpBinding), I get the following error message:

"For request in operation UploadData to be a stream the operation must have a single parameter whose type is Stream"

(I am running under .NET 3.5 SP1, btw)

Edit: I'm able to reproduce your working sample in a console application, but I'm not entirely sure what is missing between the console application and my web (.svc) host

 

Answer 4

There is no config file - that's all the code
 

Answer 5

Are you using the WebServiceHostFactory in the .svc file or adding the webHttp endpoint behavior to the endpoint?
 

Answer 6

The <webHttp /> was the issue.

The final problem appears to be a duplicate of the answer described in this question, whereby a bug in the help page generation causes the "single parameter" assertion to throw an exception.

Is there a workaround in which I can still generate a WSDL?

 

Answer 7

WSDL is meaningless for REST services - its a SOAP thing. Are you trying to support both SOAP and REST in the same service?
 

Answer 8

We are indeed trying to support SOAP + REST on the same service. We also use the WSDL to generate (non-.NET) JSON client proxies.

The solution I think I'll go with is to create two services: one with web + stream enabled and mex disabled, and the other with SOAP + byte[] and mex enabled. We'll add the "byte[]" -> "Stream" logic into our client generation code.

 

Answer 9

Yes with SOAP WCF assumes that a Stream is the complete body (and there are no query string parameters) so you'll have to provide two contracts - one for REST and one for SOAP - but they can be on the same service, just provide a separate endpoint for each
 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter