开发者

Best practice for WCF services used both locally and remotely that process large files on the filesystem?

I'm creating a WCF service that may be used either locally or remotely, and processes files sometimes using third-party components applications that unfortunately require as input a path to actual file on the filesystem, not a .net Stream or anything like that. Is there a standard approach for this situation, in terms of what the parameters to contract operations should be etc.? Although I suppose this can't be vital since it ultimately has to perform acceptably in both the local and remote cases, I'd prefer if, in the local case, it didn't have to read the whole file from the filesystem, include the contents in the message, and rematerialize it again on the filesystem, but for remote use this is necessary. Is there a way to do this e.g. by having an FSRefDoc type which serializes differently depending on whether it's used locally or remotely?

edit: To clarify: The problem is that I want to send different pieces开发者_StackOverflow中文版 of information entirely in the two cases. If I'm controlling a local service, I can just send a path to the file on the local filesystem, but if it's a remote service, I have to send the file contents themselves. Of course I can send the contents in both cases, but that means I lose performance in the local case. Maybe I shouldn't be worried about this.


OK,

Following your update, I would consider the following.

1) Create a method that takes a path. Expose this via a named pipe binding and use this locally. 2) Create a method that takes a file (stream/byte array etc). Expose this using an appropriate binding (on a different end point) for non local computers (in a LAN scenario TCP is usually your best bet).

Then all you need to do is make sure you don't duplicate the same business logic. So in a nutshell- create 2 different service interfaces, 2 different end points and 2 different bindings.


Well, you really touch on two separate issues:

  • local vs. remote service availability
  • "normal" vs. streamed service (for large files)

In general, if your service works behind a corporate firewall on a LAN, you should use the NetTcpBinding since it's the fastest and most efficient. It's fast and efficient because it uses binary message encoding (vs. text message encoding over the internet).

If you must provide a service for the "outside" world, you should try to use a binding that's as interoperable as possible, and here your choices are basicHttpBinding (totally interoperable - "old" SOAP 1.1 protocols) which cannot be secured too much, and wsHttpBinding which offers a lot more flexibility and options, but is less widely supported.

Since you can easily create a single service with three endpoints, you can really create your service and then define these three endpoints: one for local clients using NetTcpBinding, one of the widest availability using basicHttpBinding, and optionally another one with wsHttpBinding.

That's one side of the story.

The other is: for your "normal" service calls, exchanging a few items of information (up to a few KB in size), you should use the normal default behavior of "buffered transfer" - the message is prepared completely in a buffer and sent as a whole.

However, for handling large files, you're better off using a streaming transfer mode - either "StreamedResponse" if you want clients to be able to download files from your server, or "StreamedRequest" if you want clients to be able to uplaod files, or just plain "Streamed" if you send files both ways.

So besides the three "regular" endpoints, you should have at least another endpoint for each binding that handles streaming exchange of data, i.e. upload/download of files.

This may seems like a lot of different endpoints - but that's really not a problem, your clients can connect to whatever endpoint(s) are appropriate for them - regular vs. streamed and internal/local (netTcpBinding) vs. external (basicHttpBinding) as they need - and in the end, you write the code only once!

Ah , the beauty of WCF! :-)

Marc

UPDATE:
OK, after your comment, this is what I would do:

  • create a ILocalService service contract with a single method GetFile that returns a path and file name
  • create an implementation for the service contract
  • host that service on an endpoint with netTcpBinding (since it's internal, local)

[ServiceContract]
interface ILocalService
{
   [OperationContract]
   string GetFile(......(whatever parameters you need here).....);
}

class LocalService : ILocalService
{
   string GetFile(......(whatever parameters you need here).....)
   {
      // do stuff.....
      return fileName;
   }
}

and secondly:

  • create a second service contract IRemoteService with a single method GetFile which doesn't return a file name as string, but instead returns a stream
  • create an implementation for the service contract
  • host that service on an endpoint with basicHttpBinding for internet use
  • make sure to have transferMode="StreamedResponse" in your binding configuration, to enable streaming back the file

[ServiceContract]
interface IRemoteService
{
   [OperationContract]
   Stream GetFile(......(whatever parameters you need here).....);
}

class RemoteService : IRemoteService
{
   Stream GetFile(......(whatever parameters you need here).....)
   {
      // do stuff.....
      FileStream stream = new FileStream(....);
      return stream;
   }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜