我需要一个接受大型Stream的WCF服务操作,处理它并返回该流。
我使用an MSDN article on Large Data Streaming作为我需要的参考。我遵循了那篇文章中的建议。
提前提出问题:
我想知道为什么生成的服务操作在合同中指定时没有返回类型?
如果这是预期的行为,我应该如何让它传递流并返回已处理的流?
详情:
因为我需要使用MetaData同时包含输入和返回流,所以我根据需要使用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文章使用与official WCF samples.
中完全相同的合同Stream EchoStream(流数据)
但没有等效MessageContract实现的示例。样本版本可以获得预期的回报。
更新
我也尝试使用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();
答案 0 :(得分:1)
我很抱歉回答(我没有评论的声誉)。
我正在研究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();
}
}