我该如何实现WCF流式处理操作,该操作将数据流式传输、处理和返回(使用MessageContracts)



我需要一个WCF服务操作,它接受一个大流,处理它并返回该流。

我使用了MSDN上一篇关于大数据流的文章作为我所需要的参考。我听从了那篇文章中的建议。

提前提问:

  1. 我想知道为什么当我在合同中指定生成的服务操作时,它没有返回类型

  2. 如果这是预期的行为,我应该如何让它传递流并返回已处理的流

详细信息

因为我需要用元数据来伴随输入流和返回流,所以我根据需要用MessageContract属性来修饰类。

以下是我的实现的简要介绍:

消息合约:

[MessageContract]
public class InputStreamMessage
{
    [MessageHeader]
    public InputStreamHeader Header { get; set; }
    [MessageBodyMember(Order = 1)]
    public Stream Data { get; set; }
}
[MessageContract]
public class OutputStreamMessage
{
    [MessageHeader]
    public OutputStreamHeader Header { get; set; }
    [MessageBodyMember(Order = 1)]
    public Stream Data { get; set; }
}

服务合同:

[ServiceContract]
public interface IStreamService
{
    [OperationContract]
    OutputStreamMessage ProcessStream(InputStreamMessage input);
}

服务实施:

 public OutputStreamMessage DoStreamOperation(InputStreamMessage input)
 {
    //Some logic that assigns re
    OutputStreamMessage output = DoSomeNonBufferedProcessing(input);
    return output;
 }

客户端:

在客户端,我生成服务引用,并调用如下服务:

private void PerformStreamOperation()
{
    try
    {
        //
        StreamServiceReference.StreamServiceClient client = new StreamServiceReference.StreamServiceReferenceClient();
        client.Open();
        //Set Header and Parameters
        InputMessageHeader header = new InputMessageHeader();
        //...                
        //... initialize header data here
        //...                
        //... do some operation to get input stream
        var inputstream = SomeOperationToGetInputStream();
        //Perform Service stream action
        //         ____ [ Why does the generated method have the following signature, retuning void?]
        //        |     [ If this is expected, how do I use it? ]
        //        |
        //        V 
        client.DoStreamOperation(header, ref inputstream); 

        //...                
        //... Do what you wish with data
        //...                
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message.ToString(), "Stream Processing Error");
    }
}

MSDN文章使用了与WCF官方示例中完全相同的契约。

流EchoStream(流数据)

但没有等效MessageContract实现的示例。示例版本执行预期的返回。

更新

  • 我注意到服务引用具有使用预期方法签名生成的Task/Asynchronous方法。也许这意味着,当将MessageContract与Stream属性一起使用时,返回一个结构相似的对象,则必须异步调用它。我在任何地方都没有看到它的记录。将尝试使用方法-没有工作,因为我们想要同步操作
  • 我还尝试使用ChannelFactory作为生成的代理客户端的替代方案:

      EndpointAddress endpoint = new EndpointAddress("net.tcp://localhost:9910/StreamService");
      channelFactory = new ChannelFactory<IStreamService>("netTcpStreamedEndPoint");
      channelFactory.Endpoint.Contract.SessionMode = SessionMode.Allowed;
      IStreamService service = channelFactory.CreateChannel();
    

很抱歉回复(我没有评论的名声)。

我和你一样在做simmilar项目——我有一个服务,它接受大量数据流(使用MessageContracts),处理它,然后客户端可以下载这些数据。

首先-输入参数在:

 client.DoStreamOperation(header, ref inputstream); 

显示,您似乎没有生成包含MessageContracts的服务代理(请参阅http://blogs.msdn.com/b/zainnab/archive/2008/05/13/windows-communication-foundation-wcf-what-the-hell-is-always-generate-message-contracts.aspx)。这应该在客户端为您提供OutputStreamMessage和InputStreamMessage合约。

通过正确生成messageContracts,我可以在代码中同时编写这两个,而不会收到编译错误:

client.DoStreamOperation(inputStreamMessage)

   StreamServiceReference.StreamServiceClient.OutputStreamMessage outputMessage = client.DoStreamOperation(inputStreamMessage)

但基本上,第一个没有用。当然,我必须首先创建InputStreamMessage对象:

StreamServiceReference.StreamServiceClient.InputStreamMessage inputStreamMessage = new StreamServiceReference.StreamServiceClient.InputStreamMessage();

如果你愿意,我可以发布一些MessageContracts的示例。

另外,请看一下这篇文章:http://www.codeproject.com/Articles/166763/WCF-Streaming-Upload-Download-Files-Over-HTTP。在项目的早期阶段,我的消息对照看起来更相似


编辑:会话模式设置如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]

原因是我需要维护对象的信息(状态),这些信息对多个客户端来说是常见的。但这不应该影响流媒体。

这是我的装订本。我正在使用基本的http:

      <basicHttpBinding>
        <binding name="TransferBinding" transferMode="Streamed" maxReceivedMessageSize="10067108864">
        </binding>
      </basicHttpBinding>

对于上传,我使用这种消息合约:

    [MessageContract]
        public class RemoteFileInfo : IDisposable
        {
            [MessageHeader(MustUnderstand = true)]
            public string FileName;
            [MessageBodyMember]
            public System.IO.Stream FileByteStream;
}

这是在客户端定义的方法体,它调用在服务端定义的StartUpload()(您需要定义指向要上传的文件的filePath):

using (System.IO.FileStream stream = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
                           // start service client
                CalculationServiceClient client = new CalculationServiceClient();     
                RemoteFileInfo remoteFileInfo = new RemoteFileInfo(); ;
                remoteFileInfo.FileName = TextBox1.Text;
                remoteFileInfo.FileByteStream = stream;
                // upload file
                client.StartUpload(remoteFileInfo);
                // close service client
                client.Close();
                uploadStream.Close();
            }
        }

然后,我在服务端定义了StartUpload()operationContract。StartUpload合约的内部看起来像这样:

public void StartUpload(RemoteFileInfo fileInfo)
        {
            string filePath = define your filePath, where you want to save the file;           
            int chunkSize = 2048;
            byte[] buffer = new byte[chunkSize];
            using (System.IO.FileStream writeStream = new System.IO.FileStream(filePath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write))
            {
                do
                {
                    // read bytes from input stream (provided by client)
                    int bytesRead =  fileInfo.FileByteStream.Read(buffer, 0, chunkSize);
                    if (bytesRead == 0) break;
                    // write bytes to output stream
                    writeStream.Write(buffer, 0, bytesRead);
                } while (true);
                writeStream.Close();
            }
        }

相关内容

  • 没有找到相关文章

最新更新