WCF Service application: The operation must have a

2019-05-10 16:17发布

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:

enter image description here

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?

3条回答
霸刀☆藐视天下
2楼-- · 2019-05-10 16:44

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;
    }     
}
查看更多
做自己的国王
3楼-- · 2019-05-10 16:47

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 :)

查看更多
我想做一个坏孩纸
4楼-- · 2019-05-10 16:53

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

Also have a look here

查看更多
登录 后发表回答