Reputation: 457
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
Upvotes: 10
Views: 11463
Reputation: 1
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).");
}
}
}
Upvotes: 0
Reputation: 33379
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.
Upvotes: 16