WCF Service application: The operation must have a

2019-05-10 16:27发布

问题:

Possible Duplicate:
WCF Rest Webservice with stream

I'm developing a WCF .NET Framework 4.0 with C#.

I've created this WCF with this Visual Studio Template:

I need to send an image with two or three parameters. This is all OperationContract that I have (I'm asking for the last one):

[ServiceContract]
public interface IRestServiceImpl
{
    [OperationContract]
    [WebInvoke(Method = "GET",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "orders/")]
    OrderContract[] allOrders();

    [OperationContract]
    [WebInvoke(Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "filteredOrders/")]
    OrderContract[] GetOrders(IdsMessage msg);

    [OperationContract]
    [WebInvoke(Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "completeFilteredOrders/")]
    OrderContract[] LoadCompleteFilteredOrders(IdsMessage msg);

    [OperationContract]
    [WebInvoke(Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "saveEReports/")]
    Boolean SaveEReports(EReportContract[] eReports);

    [OperationContract]
    [WebInvoke(Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "saveEReport/")]
    long SaveEReport(EReportContract eReport);

    [OperationContract]
    [WebInvoke(Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "UploadPhoto/{eReportId}/{imageType}")]
    Boolean UploadPhoto(string eReportId, string imageType, Stream fileContents);
}

And this is Web.config:

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="EReportService.RestServiceImpl" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" contract="EReportService.IRestServiceImpl" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <bindings>
      <webHttpBinding>
        <binding maxReceivedMessageSize="2097152" maxBufferSize="2097152" transferMode="Streamed"/>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <connectionStrings>

  </connectionStrings>
</configuration>

When I run service I get the following exception:

The operation must have a single parameter whose type is Stream

If I do this:

[OperationContract]
[WebInvoke(Method = "POST",
    ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate = "UploadPhoto")]
Boolean UploadPhoto(Stream fileContents);

It works perfectly but I need to send more data with image.

This service is exposed for an Android tablet application. The following code show how I'm sending now images to server:

public static Boolean sendImage(String url, String filePath)
{
    try
    {
        MultiValueMap<String, Object> formData;

        Resource resource = new FileSystemResource(filePath);

        // populate the data to post
        formData = new LinkedMultiValueMap<String, Object>();
        formData.add(OrderSpringController.FILE, resource);

        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json")));

        // Sending multipart/form-data
        requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);

        // Populate the MultiValueMap being serialized and headers in an HttpEntity object to use for the request
        HttpEntity<MultiValueMap<String, Object>> requestEntity = 
                new HttpEntity<MultiValueMap<String, Object>>(formData, requestHeaders);

        GsonHttpMessageConverter messageConverter = new GsonHttpMessageConverter();
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
        messageConverters.add(messageConverter);

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate(true);
        restTemplate.getMessageConverters().add(messageConverter);

        // Make the network request, posting the message, expecting a String in response from the server
        ResponseEntity<Boolean> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity,
                Boolean.class);

        // Return the response body to display to the user
        return response.getBody();
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }
    return null;
}

The error occurs when browsing to metadata endpoint (http://localhost:2351/RestServiceImpl.svc).

How can I send an image and parameters?

回答1:

If you switch to (BasicHttp or WSHttp )Binding then you can achieve your goal by composing a single data type including all your custom parameters via properties and the Stream object itself. Then you are making use of messaging style instead of RPC conversation. And pls pay attention to [MessageContract] family of WCF DTO decorators.

[ServiceContract]
public interface ITransferService
{
    [OperationContract]
    RemoteFileInfo DownloadFile(DownloadRequest request);

    [OperationContract]
    void UploadFile(RemoteFileInfo request); 
}
[MessageContract]
public class DownloadRequest
{
    [MessageBodyMember]
    public string FileName;
}

[MessageContract]
public class RemoteFileInfo : IDisposable
{
    [MessageHeader(MustUnderstand = true)]
    public string FileName;

[MessageHeader(MustUnderstand = true)]
public long Length;

[MessageBodyMember]
public System.IO.Stream FileByteStream;

public void Dispose()
{ 
    if (FileByteStream != null)
    {
        FileByteStream.Close();
        FileByteStream = null;
    }
}   

}

This has necessary code http://www.codeproject.com/Articles/166763/WCF-Streaming-Upload-Download-Files-Over-HTTP

But I strongly suggest WCF: using streaming with Message Contracts and http://blogs.msdn.com/b/carlosfigueira/archive/2011/03/25/wcf-streaming-inside-data-contracts.aspx

This is a MUST, as well :)



回答2:

Try reordering your parameters so that the Stream ist the last one.

Also have a look here



回答3:

I have created new type and selalize it

it contains the 3 values ( stream , reportid ,reporttype )

below is the code

namespace WcfService5
{

    [ServiceContract]
    public interface IService1
    {    
        [OperationContract]
        Boolean UploadPhoto(data fileContents);
    }

    [Serializable]
    public struct data 
    {
        System.IO.Stream mystream;
        string ereport;
        string reporttype;
    }
}

here is the service code

public class Service1 : IService1
{
    public bool UploadPhoto( data value)
    {
        return false;
    }     
}