2

I need to return a big byte array from a WCF server.

The problem is - in order to return such an array - I need to create one - and when creating such an array - it automatically goes to the Large Object Heap - meaning that when the service is stressed - I'm getting a real problem in memory usage and management.

I thought about using unmanaged memory to avoid using large managed byte arrays - but still - how can I return such an array from a WCF service?

Is there any way of returning a "Stream" of bytes from a WCF service that does not include actually creating a managed byte array? I know that WCF itself uses a BufferManager - so if it just reads my unmanaged memory and uses its buffer management to store it before sending - I hopefully won't have a problem.

Roy Reznik
  • 2,040
  • 4
  • 22
  • 28
  • Can you try to write it to a file and let the clients download the file? – Ravi Y Nov 20 '12 at 15:41
  • 1
    Yes you can return `Stream`. Why don't you try. – L.B Nov 20 '12 at 15:41
  • ryadavilli - I'm afraid that writing and reading from a file is 1. not secure in some cases (when the data is sensitive) and 2. requires IO which is bad in terms of performance – Roy Reznik Nov 20 '12 at 15:42
  • L.B - Returning an UnmanagedMemoryStream is impossible - In order to return a MemoryStream - it has to be backed by a byte array... – Roy Reznik Nov 20 '12 at 15:43
  • @RoyReznik FileStream is also stream :) You can also implement your own stream which doesn't load all the data into the memory at once. – L.B Nov 20 '12 at 15:45

1 Answers1

2

You can use WCF's Streaming Mode. From that page:

  1. To stream data, the OperationContract for the service must satisfy two requirements:

    a. The parameter that holds the data to be streamed must be the only parameter in the method. For example, if the input message is the one to be streamed, the operation must have exactly one input parameter. Similarly, if the output message is to be streamed, the operation must have either exactly one output parameter or a return value.

    b. At least one of the types of the parameter and return value must be either Stream, Message, or IXmlSerializable.

  2. Streaming must be enabled on the binding. You set a TransferMode property, which can take one of the following values:

    a. Buffered,

    b. Streamed, which enables streaming communication in both directions.

    c. StreamedRequest, which enables streaming the request only.

    d. StreamedResponse, which enables streaming the response only.

There are some decent examples on that page as well, including how to write back a custom stream (it's toward the bottom).

For more background info on encoding, streaming and sessions, and some security considerations when using streaming, see this MSDN page.

schellack
  • 10,144
  • 1
  • 29
  • 33
  • Sounds very promising - I'll check it out. – Roy Reznik Nov 20 '12 at 15:45
  • Unfortunately, after checking the restrictions - my method also returns 2 additional output parameters (that are a must...) - Any way to bypass that? – Roy Reznik Nov 20 '12 at 16:03
  • 2
    You can try passing the parameters in the message header by using the OperationContext.OutgoingMessageHeaders Property. From http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext.outgoingmessageheaders.aspx: "Use this property to add reply headers that are sent by a service operation or request headers that are sent by a WCF client object." There are some pretty good examples of that at http://stackoverflow.com/questions/964433/how-to-add-a-custom-header-to-every-wcf-calls/ – schellack Nov 20 '12 at 17:01
  • 1
    Found a much simpler way - Just create a class that has the MessageContract attribute - all parameters (that are not streamed) should have the MessageHeader attribute and the streamed parameter should have the MessageBodyMember attribute – Roy Reznik Nov 20 '12 at 20:39