Restful WCF Service - returning byte[]? - wcf

I'm working with a RESTful WCF service. One of the service methods returns byte[] (which contains a file).
On the client side, I have some code that uses the WebRequest class to invoke that particular service method. Using the WebRequest, I'm getting the response stream like:
Stream stream = webReq.GetResponse().GetResponseStream();
From this stream, I am then reconstructing a byte[] and then outputting the File locally. The problem is that the reconstructed file on the client-side doesn't resemble the file that was returned from the service side (I get a corrupt PDF file that is much larger in size than the one sent from the service side). Just before the service method returns the byte[], I outputted that byte[] to disk on the service side and it created the file fine... This points to something going wrong between that method returning the byte[] and my client side reconstructing the byte[] from a Stream on the client side... to reconstruct the byte[] from the Stream, I'm using the following method which someone posted in the past on stackoverflow:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Any ideas what could be going wrong?

I guess that the response from the server contains some envelope in addition to the raw bytes. Like a XML envelope or something. Which would of course suppose that the bytes are base64 encoded string in the response because you cannot store binary data into XML. It would also explain why you are getting a bigger buffer on the client than the actual PDF that the server has sent.
This will of course depend on what binding your WCF service uses and how is it configured. When you dump the contents of the MemoryStream you are reading on the client what exactly do you see? This should give you further hints on how the actual PDF file is encoded in the HTTP response body.

Related

Why JAX-RS Response.fromResponse(anotherResponse) not copying the entity?

This is part of a JAX-RS server which receives a response from another server and sends the same response back to its client.
This copies the entity from anotherResponse to responseForClient:
Response responseForClient = Response.fromResponse(anotherResponse).entity(anotherResponse.readEntity(InputStream.class)).build();
This doesn't copy the entity:
Response responseForClient = Response.fromResponse(anotherResponse).build();
The second one should also work as JAX-RS Response.fromResponse() should copy the entity also.
Why setting the entity is required?
I am using RestEasy-3.0.
You have to consume the InputStream before calling fromResponse because it only will copy the response. The JAX-RS won't do it automatically, and if you provide the new instance to the client then the entity will not be consumed
See the documentation of fromResponse
public static Response.ResponseBuilder fromResponse(Response response)
Create a new ResponseBuilder by performing a shallow copy of an existing Response.
The returned builder has its own response headers but the header values are shared with the original Response instance. The original response entity instance reference is set in the new response builder.
Note that if the entity is backed by an un-consumed input stream, the reference to the stream is copied. In such case make sure to buffer the entity stream of the original response instance before passing it to this method.
Buffer the response reading the InputStream to a byte array
InputStream is = anotherResponse.readEntity(InputStream.class);
byte[] bytes = IOUtils.toByteArray(is);
ByteArrayInputStream in= new ByteArrayInputStream (bytes);
This code is equivalent to yours
Response responseForClient =
Response.fromResponse(anotherResponse).entity(in).build()

How do stream a file from WCF that didn't originate from a filesystem. (sharepoint content database)

I'm trying to return a stream in WCF 3.5 using a REST-Style URL instead of SOAP. The idea is to read a file from SharePoint 2010, then pass it back to the client. (We have reasons for doing it this way instead of using SharePoint services, but I digress.) It appears as though the only way to send the file is by writing it to the filesystem using one FileStream, then using File.OpenRead to return the stream back to the client. Using a MemoryStream doesn't seem to work. IE prompts for the file save, but the file comes down as like 2KB and then can't be read of course because it's not all there. Any ideas?
SPListItemCollection lookupFld2 = docLibrary.GetItems(spQuery2);
if (lookupFld2.Count > 0)
{
WebOperationContext.Current.OutgoingResponse.ContentType =
"application/octet-stream";
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Content-Disposition","attachment; filename=" + lookupFld2[0].File.Name);
MemoryStream memoryStream =
(MemoryStream)lookupFld2[0].File.OpenBinaryStream();
memoryStream.Position = 0;
return memoryStream;
}
Technically, OpenBinaryStream only returns a general Stream instance NOT a MemoryStream (http://msdn.microsoft.com/en-us/library/ms470901.aspx). If you want a MemoryStream you need to create a new one and copy the contents from the BinaryStream into the MemoryStream then reset the position and return it.

How to deserialise a proto that was received as a byte[]

I am using the Spring.Rest framework.
If we receive a 402, the body will contain a proto which in turn will contain various error information.
The Exception raised on a 402 is an instance of Spring.Rest.Client.HttpClientErrorException.
The response within the exception is an instance of Spring.HttpResponseMessage.
The Body within the response is of type byte[].
This means I have a byte[] while the Deserialiser is expecting a Stream.
In order to deserialise the proto contained in the body I have done the following:
MemoryStream mStream = new MemoryStream();
mStream.Write(exception.Response.Body,0,exception.Response.Body.Length);
var proto = Serializer.Deserialize<XXXRestProtoException>(mStream);
when I inspect the proto returned, its properties are all null.
Is my approach correct, or do I need to do more before presenting the Stream to the Deserialize method?
We have confirmed that the proto definitions used on Client and Server are in sync and the body is well formed on the server.
The Stream produced by this code has the same length and contents as the given byte[], which in turn matches the content-length header.
If you Write to a stream, then the Position is left at the end of the stream; 2 simple options:
rewind the stream; between the Write and the Deserialize, put:
ms.Position = 0;
initialize the stream from the blob:
MemoryStream mStream = new MemoryStream(exception.Response.Body);
I'd usually use the latter.

creating file from returned byte array via WCF Rest Service

I am working on creating a WCF rest service. I have a function that will return a byte array of a file created by the service. I was wondering how I can create this file, from the byte array on the client side. This is in C#.
Simply write all received bytes to the file:
File.WriteAllBytes("filename.bin", receivedBytesArray);
Save stream to file:
Stream receivedStream = // do some staff to receive stream
using (FileStream stream = File.OpenWrite("myfilepath.bin"))
{
receivedStream.CopyTo(stream);
}

Getting around base64 encoding with WCF

I'm using WCF, REST and "pretty URI's" as shown in this blog post with the Online Template for VS 2010 .NET 4.0:
http://christopherdeweese.com/blog2/post/drop-the-soap-wcf-rest-and-pretty-uris-in-net-4
I have one problem though.
I want to return a a raw byte[] array but it automatically gets base64 encoded.
Unfortunately for my program base64 encoding is not acceptable because it will be too computationally intensive.
Is there a way for me to tell WCF NOT to base64 encode?
[WebGet(UriTemplate = "{id}")]
public byte[] Get(string id)
{
byte[] data = new byte[1024];
return data;
}
Appears to my web browser as:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
Use Stream as your return type.