如何实现WCF Streaming操作,用于流式处理数据,处理数据,将数据流回传(使用MessageContracts)?
我有一个接受大型流的WCF服务操作的要求,处理它并返回该流。如何实现WCF Streaming操作,用于流式处理数据,处理数据,将数据流回传(使用MessageContracts)?
我用an MSDN article on Large Data Streaming作为我需要的参考。我遵循了那篇文章中的建议。
问提前了一个问题:
我想知道为什么当我在合同中注明它生成的服务操作不会有返回类型?
如果这是预期的行为,我应该如何让它传递一个流并返回一个处理过的流?
详细:
因为我需要陪伴输入和与元数据中返回流,我饰类与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(Stream data)
但没有例子一个等效的MessageContract实现。样本版本预期会有回报。
更新
- 我注意到服务引用具有与预期的方法签名生成任务/异步方法。也许这意味着当使用带有Stream属性的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();
对不起用于在回答中回复(我没有征求意见的声誉)。
我正在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)
但basicaly第一个有没有用。 当然,我必须首先创建InputStreamMessage对象:
StreamServiceReference.StreamServiceClient.InputStreamMessage inputStreamMessage = new StreamServiceReference.StreamServiceClient.InputStreamMessage();
如果你想,我可以张贴我的MessageContracts的一些样品。
另外,请看看这篇文章:。我messagecontracs看着simmilar在项目的早期阶段
编辑: 会话模式设置是这样的:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
的原因是,我需要保持信息(州)关于对象,这对于多个客户端来说很常见。但是这不应该影响流式传输。
这是我的绑定。使用im基本HTTP:
<basicHttpBinding>
<binding name="TransferBinding" transferMode="Streamed" maxReceivedMessageSize="10067108864">
</binding>
</basicHttpBinding>
对于上传,使用这种messagecontract的进口:
[MessageContract]
public class RemoteFileInfo : IDisposable
{
[MessageHeader(MustUnderstand = true)]
public string FileName;
[MessageBodyMember]
public System.IO.Stream FileByteStream;
}
这是在客户端定义的方法的正文中,调用StartUpload()在服务侧限定(您需要定义文件路径,导致你要上传的文件):
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();
}
}
它解决了问题吗? – JakubJ 2015-03-18 15:56:49
Hi @JakubJ。感谢回复。你介意发布一个示例实现?你还使用了什么'SessionMode',你的绑定配置如何?它是连续的数据流还是你在服务操作的某个时候关闭它? codeproject文章不是我在找什么。我想发送并返回一个连续的,不间断的流 – user919426 2015-03-22 14:42:05
你好。连续流的意思是什么?例如,如果您正在流式传输实况视频? Iam使用流传输大文件 - 客户端选择文件传输,点击“上传”按钮,整个文件被传输到服务端。我会在几分钟内更新我的答案,并附上我的一些实施。 – JakubJ 2015-03-22 17:00:21
您是否尝试过使用'ChannelFactory',而不是添加一个服务引用,可能有助于显示问题所在。 – 3dd 2015-03-16 06:28:52
是的,我已经使用了ChannelFactory。将发布更新 – user919426 2015-03-16 06:50:32
好吧,使用'ChannelFactory'的结果是什么,你是否尝试切换跟踪并查看是否有任何错误弹出? – 3dd 2015-03-16 07:34:14