WCF:使用消息契约进行流传输

20

我正在尝试使用带有消息契约的WCF流,因为除了流本身之外,我需要其他参数。

基本上我正在创建一个文件上传和下载服务,并在其上添加一些附加逻辑。

不幸的是,当我尝试从浏览器访问服务以检查一切是否正常时,我会收到以下错误:

'/'应用程序中的服务器错误。 合同'IFileTransferService'中的操作'UploadFile'使用具有SOAP标头的MessageContract。 SOAP标头不受None MessageVersion支持。

不幸的是,对此进行谷歌搜索没有产生任何有助于我的显着结果。你们能帮我吗?这里是服务的详细信息(由于空间原因,我已删除了下载部分)。

[ServiceContract(Namespace = "http://www.acme.org/2009/04")]
public interface IFileTransferService
{
    [OperationContract(Action = "UploadFile")]
    void UploadFile(FileUploadMessage request);
}

[MessageContract]
public class FileUploadMessage
{
    [MessageHeader(MustUnderstand = true)]
    public FileMetaData Metadata { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream FileByteStream { get; set; }
}

[DataContract(Namespace = "http://schemas.acme.org/2009/04")]
public class FileMetaData
{
    [DataMember(Name="FileType", Order=0, IsRequired=true)]
    public FileTypeEnum fileType;

    [DataMember(Name="localFilename", Order=1, IsRequired=false)]
    public string localFileName;

    [DataMember(Name = "remoteFilename", Order = 2, IsRequired = false)]
    public string remoteFileName;
}

我尝试过使用basichttpbinding和自定义http绑定,但没有取得积极的效果:

<customBinding>
    <binding name="customHttpBindingStream">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647"/>
    </binding>
</customBinding>

更新:在线阅读文档后,看起来使用MessageContracts进行流式传输确实是可能的。例如,请参考MSDN (大数据和流式传输):

流传输编程模型

流传输的编程模型非常简单。要接收流式数据,请指定一个带有单个Stream类型输入参数的操作契约。要返回流式数据,请返回一个Stream引用。[...] 同样适用于消息契约。如下所示的消息契约中,您的消息契约中只能有一个主体成员是流。如果您想通过流传输附加信息,则必须将此信息放在消息头中。消息正文仅专门保留流内容。

[MessageContract]
public class UploadStreamMessage
{
   [MessageHeader]
   public string appRef;
   [MessageBodyMember]
   public Stream data;
} 

我看过一些博客文章,这些人完成了非常类似于我正在尝试实现的文件上传和下载服务(例如这里)。

更新2: 我已经尝试创建一个小型控制台应用程序并使用basicHttpBinding自托管服务,那里它运行得非常好。我开始相信问题可能是在IIS上托管的问题。有什么想法吗?

更新3: 请看我的答案。


我认为在MessageBodyMember属性中,Order = 1是多余的,因为你只有一个正文元素。 - Ohad Schneider
3个回答

8

我最终发现错误的原因:与Soap版本、流等无关...我只是拼错了自己服务的名称!使用FileTransfer而不是FileTransferService

最终,basicHttpBinding完全正常,我不需要使用自定义绑定。

原始(糟糕)版本:

<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransfer">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

新版本(修复版):
<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransferService">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

尽管如此,我仍然无法说错误消息有助于理解这里发生了什么...... 如果您对整个服务感兴趣,可以在我的博客上找到更多详细信息,链接如下:使用WCF进行文件传输

2
你需要在请求和响应中都进行流媒体传输(即传输大量数据)吗?还是只需要在响应中进行(通常是下载文件或大型数据集)?
如果只需要在响应中进行,你应该尝试将传输模式设置为“StreamedResponse”:
<customBinding>
    <binding name="customHttpBindingStream">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport transferMode="StreamedResponse" 
                       maxReceivedMessageSize="2147483647"/>
    </binding>
</customBinding>

"Streamed"设置将双向流动 - 发往服务器的请求和来自服务器的响应都将被流式传输。往往情况下,这并不是理想的情况。

Marc


嗨Marc,正如我在问题中提到的那样,我正在创建一个文件服务,允许上传和下载文件。因此,我确实需要能够双向流传输。你认为这与我遇到的错误有关吗? - Stefano Ricciardi
不确定 - 我以前从未见过将流式处理与消息契约结合在一起的组合......我曾经看到过只有从服务器下载很大(下载文件)的情况,并且将TransferMode设置为StreamedResponse有所帮助。 - marc_s
如果仅使用DataContract(而不使用消息契约部分),它是否有效 - 仅用于测试,以查看结果。 - marc_s
是的,它可以使用Stream对象或DataContract作为参数来工作。 - Stefano Ricciardi
Marc,看一下我几分钟前发的最新更新。我已经尝试过自托管服务,在那里它可以工作。现在我正在调查自托管和IIS托管之间的区别是什么。 - Stefano Ricciardi
显示剩余2条评论

0

我在使用“WCF数据服务”模板生成svc文件时出现了错误,而不是使用“WCF服务”模板。通过更正服务主机文件,问题得到解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接