WCF Rest Webservice with stream
Asked Answered
Q

2

10

I read the following post with interest as it is an exact replica of the problem I am experiencing (and driving me insane) "For request in operation UploadFile to be a stream the operation must have a single parameter whose type is Stream." -http://social.msdn.microsoft.com/Forums/en/wcf/thread/80cd26eb-b7a6-4db6-9e6e-ba65b3095267

I have pretty much followed all code/examples I have found and yet still cannot get around this error - http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-receiving-arbitrary-data.aspx

All I would like to achieve is to post an image(jpeg/png) from an android device using the standard filename/stream parameters.More than likely it is something simple that I have misconfigured, misunderstood or left out but I need to have a solution for proof of concept.

 public interface IConXServer
    {
    [OperationContract]
    [WebInvoke(UriTemplate = "UploadImage({fileName})", Method="POST")]
    void UploadImage(string fileName, Stream imageStream);
    }

 public class ConXWCFServer : IConXServer
    {
    public void UploadImage(string fileName, Stream imageStream)
       {
       //implement image save
       }
    }

web.config settings -->

<standardEndpoints>
   <webHttpEndpoint>
       <standardEndpoint name="webHttpEndpoint" helpEnabled="false"/>
   </webHttpEndpoint>
</standardEndpoints>

<bindings>
    <webHttpBinding>
        <binding name="webHttpBinding" transferMode="Streamed"/>
    </webHttpBinding>
</bindings>

<behaviors>
    <endpointBehaviors>
        <behavior name="webHttpBehavior">
            <webHttp/>
        </behavior>
    </endpointBehaviors> 
    <serviceBehaviors>
        <behavior>
            <serviceMetadata httpGetEnabled="false"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <serviceThrottling maxConcurrentCalls="2147483647"  maxConcurrentSessions="2147483647"/>
        </behavior>
    </serviceBehaviors>
</behaviors>

Using vs2010 and IIS Express. If I comment out the above method all the others methods work and return data as well as the wsdl query

Regards and thanks in advance Kern

Quincey answered 16/6, 2011 at 2:26 Comment(2)
For request in operation UploadFile to be a stream the operation must have a single parameter whose type is Stream. The error occurs when browsing to metadata endpoint.Quincey
(5 years later..) This one's killing me. I have two WCF service projects, both .Net 4.5.1. In one, a service with Stream as 1 of 3 parameters works perfectly, in the other, it throws this exception. I have File-Compared the two web.configs, and they're identical.... but I just can't fix this issue. Even recreating the "faulty" service doesn't fix it. I'm baffled.Infundibulum
R
16

You mention WSDL, which leads me to believe you're getting the error while trying to browse the metadata endpoint for the service. So, first off, WSDL and REST don't go together, so you shouldn't expect to use it at all for a REST interface. Forget the service metadata concept even exists in the REST world.

Next While it's true the REST's webHttpBinding supports parameters in front of the Stream body parameter, other bindings do not and there must either be a single Stream parameter or a message contract with headers and a stream body.

So, in the end, the problem is not with the REST webHttpBinding at all, I bet it works just fine. If it doesn't I would be absolutely shocked because you're not doing anything that shouldn't work in that department. The problem is that you're expecting the metadata endpoint to generate WSDL for the service contract you've defined and that's just not supported.

Rolph answered 16/6, 2011 at 3:1 Comment(5)
Thanks for insight. Let me see if I understand(my WCF is limited) In effect you are saying that a REST endpoint will accept parameters/stream as described in my attempt and that the error is actually generated by the metadata endpoint - which I inadvertently forgot was a seperate endpoint and therefore a seperate binding mechanism - which only supports a single stream parameter?Quincey
Correct, the WSDL generator implementation is made for the SOAP/RPC service contracts and on those you can't either have individual parameters of various intrinsic or data contract types, a Stream or a message contract. You can't mix the three together. So, when it tries to generate metadata for your REST service contract, where it's perfectly valid to throw a Stream parameter in the mix as the last parameter for the body, it bombs out with the error your seeing because it never expects to come across a signature like that.Rolph
Ok. These rest services were set up for a mobile html5/css/js proof of concept - which has been flagged in favour of native coding. Is REST even applicable in this scenario on a mobile device or should we consider switching back to basicHttp? We would like to have WSDL and the ability to receive XML (POX) without the SOAP but I am guessing this is a conflict?Quincey
If you want to use WSDL/RPC then you don't want to use REST... the two are conflicting ideals. :) Either one would work just fine, but depending on your mobile dev platform you may have a more difficult time working with SOAP. If you're just sending around POX and don't require the benefits that SOAP (i.e. interop with the WS-* standards) then you should just go with webHttpBinding w/XML encoding and be done with it. REST is much more than just HTTP+XML , it's a different way of designing web APIs. You don't necessarily have to get caught up in all that though if RPC style suits your needs.Rolph
Hi, I'm getting the same error when I open localhost:6842/ImageService.svc on Internet Explorer. Do I have this problem because I'm trying to see WSDL on Internet Explorer? In other words, is this the same error you are talking? I've asked this question: #13601738Kenosis
M
0

I do it this way and it'works.

Add Factory Class to webservice (WcfService2.ServiceFactory)

<%@ ServiceHost Language="C#" Debug="true" Service="WcfService2.Service1" CodeBehind="Service1.svc.cs" Factory="WcfService2.ServiceFactory" %>

My Interface:

public interface IService1

 {

[OperationContract]
        [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest, Method = "POST",
         RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "UploadFile/{fileName}")]

        void UploadFile(string fileName, Stream fileContent);


 }

My Method:

public void UploadFile(string fileName, Stream fileContent)
        {

            var pathfile = "\\\\SERVER\\TravelsRequestFiles";
            using (var fileStream = new FileStream(string.Concat(pathfile, "\\", fileName), FileMode.Create, FileAccess.Write))
            {
                fileContent.CopyTo(fileStream);
            }

        }

my FactoryClass:

public class ServiceFactory : ServiceHostFactory

    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)

        {
            return new MyServiceHost(serviceType, baseAddresses);
        }

        class MyServiceHost : ServiceHost

        {
            public MyServiceHost(Type serviceType, Uri[] baseAddresses)
              : base(serviceType, baseAddresses)
            {
            }

            protected override void InitializeRuntime()
            {
                ServiceEndpoint endpoint = this.Description.Endpoints[0];
                endpoint.Behaviors.Add(new EndpointBehaviors());

                base.InitializeRuntime();
            }
        }
    }

I added a EndpointBehaviors class, wich it find de operation UploadFile and remove its DataContractSerializerOperationBehavior, and then works!

public class EndpointBehaviors: IEndpointBehavior

    {

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {

            ContractDescription cd = endpoint.Contract;
            foreach (DispatchOperation objDispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
            {
                if (objDispatchOperation.Name.Equals("UploadFile"))
                {
                    OperationDescription myOperationDescription = cd.Operations.Find("UploadFile");

                    DataContractSerializerOperationBehavior serializerBehavior = myOperationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
                    myOperationDescription.Behaviors.Remove(serializerBehavior);                
                }
            }
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            BindingElementCollection elements = endpoint.Binding.CreateBindingElements();
            WebMessageEncodingBindingElement webEncoder = elements.Find<WebMessageEncodingBindingElement>();
            if (webEncoder == null)
            {
                throw new InvalidOperationException("This behavior must be used in an endpoint with the WebHttpBinding (or a custom binding with the WebMessageEncodingBindingElement).");
            }           
        }
    }
Milissamilissent answered 14/10, 2019 at 15:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.