Tenshiko
Tenshiko

Reputation: 1470

Downloading image as byte array through WCF fails

I'm stuck with an annoying problem.

There is a database containing images as byte arrays. I use the following method to get the images back from the byte arrays:

// byte[] ImageData contains the image loaded from the DB.

var stream = new MemoryStream(ImageData);
Image img = Image.FromStream(stream);
img.Save("D://Test/test.png", ImageFormat.Png);

When the Client requests an image from the server I run the above code on both server AND client side (with different filenames).

The thing is: when I'm on server side, this works wonderfully. File saves, and I can open and view the image in Windows Photo Viewer.

But when I get to client side, it seems like there have been some changes to this byte array, and Image throws an exception complaining about invalid parameters.

Also, I tried to save the byte array as it is with .png extension and then open it with Photo Viewer. It also fails.

What could possibly happen to my data when travelling through WCF, that causes the faulty byte array?

EDIT: Results of comparing files on server and client side.

Arrays look the same on both sides, EXCEPT on client side they miss the last few bytes. Even though the array on client side has actually LESS data, the file size says the client side image is BIGGER (by exactly 55 bytes) than it was on the server side.

The server is nothing fancy. Client calls DownloadImg in a BackgroundThread, but directly on the service reference like this:

var result = _service.DownloadImg(id);

Service interface:

[ServiceContract(Namespace="http://cannottellyou.com")]
public interface IImageService
{
    [OperationContract]
    DBImage DownloadImg(int id);
}

The Image object:

[DataContract(Namespace="http://cannottellyou.com")]
public class DBImage
{
    [DataMember]
    public virtual byte[] Data { get; set; }
}

The function that loads the image on server:

public class ImgService: IImageService
{
    public DBImage DownloadImg(int id)
    {
        var img = new DBImage();

        //That is where we get the byte array, and where I tested the image with the above code, and it works. I am sorry I cannot tell you more about this part...
        // img.Data holds the byte[] by now

        return img;
    }
}

The binding:

<binding name="BinBinding" messageEncoding="Mtom"
    closeTimeout="00:10:00"
    openTimeout="00:01:00"
    sendTimeout="00:05:00"
    receiveTimeout="00:10:00"
    maxReceivedMessageSize="67108864"
    maxBufferPoolSize="65536">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2097152"
        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    <security mode="None">
        <message  />
    </security>
</binding>

Upvotes: 0

Views: 2480

Answers (3)

Tenshiko
Tenshiko

Reputation: 1470

It seems like this was caused by the Mtom encoding. We switched to Base64 and everything is fine now.

But still don't know exactly why...

Upvotes: 1

Ricibob
Ricibob

Reputation: 7705

Normally if the array is bigger than the limits set in the various binding parameter I would expect an exception not a truncated array and its weird that the bytes are missing regardless of the org image/array size. I think you must be doing some odd somewhere. But just to be sure Id try with read quota bumped up:

   <readerQuotas maxDepth="32"
        maxStringContentLength="10000000" maxArrayLength="10000000"
        maxBytesPerRead="10000000" maxNameTableCharCount="10000000" />

and buffers the same:

 maxBufferPoolSize="10000000" maxBufferSize="10000000" maxReceivedMessageSize="10000000">

but from your description I'm not sure this will help.

Upvotes: 0

Tom Kerkhove
Tom Kerkhove

Reputation: 2191

I have no clue but you can try this :

  • You're returning DBImage, have you tried just returning byte[] Data?
  • Are you sure you're image isn't bigger than your bindingsetting?

Upvotes: 0

Related Questions