Sending large data from WCF Server to Delphi Client

对着背影说爱祢 提交于 2019-12-25 05:16:19

问题


I need to create a WCF Service that will have a download file function. This WCF will be consumed by a Delphi application.

The problem: The files that will be downloaded are very large and may cause memory problems on Delphi side. So far, I have this code:

[OperationContract]
byte[] DownloadFile(string filePath);

But this code will cause the client app to hold all data in memory which can be an issue.

I have read that WCF is capable of streaming data as you can read at: How to: Enable Streaming

But I have a question regarding this piece of code cut from MSDN:

[OperationContract]
Stream GetStream(string data);

On the client side I want to pass a TFileStream to the function. By using TFileStream every byte read will go directly to the disk. But the function RETURNS a stream and what I want will not be possible since the stream will not a parameter to the function.

How can I download a file from a WCF service directly to the disk?


回答1:


I have found that relying on "built-in" streaming capability in WCF when working with other (non-.NET) clients is a big source for strange problems...

Basically we solve this kind of scenario by defining:

[OperationContract]
string DownloadFile(string filePath);

The method generates a HTTP(S) url and returns it...

This way any http-capable client can work with the data in a robust fashion...

BEWARE that this makes the server a bit more complicated since you now need to have some mechanism to generate (and serve HTTP GET on) URLs (security, "globally" unique, only usable for a limited time etc.).

BUT the big advantage is that any client out there (mobile or some strange embedded device or whatever you might encounter) will be able to implement this scheme as long as it has http-support available (Delphi has some very good http-client options).




回答2:


First of all, I'm not sure whether you can consume a streaming WCF service at all in Delphi 2010. If you can, then it works as follows:

The WCF service must be a streamed service, which means that you need to set the transferMode of the binding to Streamed or StreamedResponse. If you want to pass in a string as parameter, it must be StreamedResponse, otherwise, the parameter must be a stream as well.

Having a streamed service also means that there can be no method that does not return a stream or void. It is, for example, not possible to have the following two methods in the same service when it is a streamed service.

Stream GetStream(string s);
int GetInteger(string s);

Also it is not possible to have:

Stream GetStream(string s);

in a service which is configured to be Streamed, as the parameter would have to be a stream, too.

It is not possible to call the method with a stream which will be "filled", even if you make the method take a Stream parameter - not the real instance of Stream is passed back and forth at that point, but the content is actually copied back and forth.

In Delphi you'd get a stream as a result of the method call. You can then copy the contents of that stream into a TFileStream as you'd do if the source was another stream in Delphi. Code for that can be googled. Basically Adriano has posted something that should work. Basically: Read from the source stream, write to the destination stream until everything was read and written, or you could try something like that:

stream1 := wcfServiceClient.GetTheStream();
try
    stream2:= TFileStream.Create('to.txt', fmCreate);
    try
        stream2.CopyFrom(stream1, stream1.Size);
    finally
        stream2.Free;
    end;
finally
    stream1.Free;
end;

Again: This works only under the assumption that you can access a WCF streamed service from Delphi as you'd access it from C# or VB.NET.



来源:https://stackoverflow.com/questions/10818391/sending-large-data-from-wcf-server-to-delphi-client

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!