Daniel Daniel - 3 months ago 41
C# Question

Dropzone JS Upload to WCF Getting Wrong Data

First of all, I'm new to both WCF services and dropzone JS, but I'm trying to combine the two to create a simple image uploader. I've got my WCF working correctly for the metadata that I've uploaded to through it (so I know it's passing things cross domain correctly), but the Stream that I've captured from Dropzone doesn't match the image that I dropped. In fact, every single image dropped results in the same encoded string server-side ...

For example, I've used this star image as a test, and by uploading the image to a base64 online converter, I can see that the beginning of the base64 string looks like this:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAADbCAMAAABOUB36AAAAwFBMVEX...


However, when I debug my WCF code, the base64 converted string looks like this:

LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5T1RUV0I1RFZZdTVlM2NTNQ0KQ29udG...


This string above is the same one for created for every image that I try to send.

So now for all the applicable code pieces. I've got a simple webpage in one project and the WCF related files in another project in the same solution.

Index.html:

<div class="col-lg-12">
<form action="http://localhost:39194/ImageRESTService.svc/AddImageStream/"
class="dropzone"
id="dropzone"></form>
</div>
...
Dropzone.options.dropzone = {
maxFilesize: 10, // MB
};


OperationContract:

/* Stores a new image in the repository */
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "AddImageStream/")]
void AddImageStream(Stream img);


AddImageStream implementation:

public void AddImageStream(Stream img)
{
//try to save image to database
byte[] buffer = new byte[10000];
int bytesRead, totalBytesRead = 0;
string encodedData = "";

do
{
bytesRead = img.Read(buffer, 0, buffer.Length);
encodedData = encodedData + Convert.ToBase64String(buffer,
Base64FormattingOptions.InsertLineBreaks);
totalBytesRead += bytesRead;
} while (bytesRead > 0);
}


Webconfig applicable pieces:

<services>
<service name="ImageRESTService.ImageRESTService" behaviorConfiguration="serviceBehavior">
<endpoint address="" behaviorConfiguration="web" contract="ImageRESTService.IImageRESTService" binding="webHttpBinding" bindingConfiguration="webHttpBinding"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" maxReceivedMessageSize="2147000000" />
</webHttpEndpoint>
</standardEndpoints>
<bindings>

<webHttpBinding>
<binding crossDomainScriptAccessEnabled="true" name="ImagesBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" />
<binding name="webHttpBinding" transferMode="Streamed" maxReceivedMessageSize="2147483647" maxBufferSize="10485760" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="1000000" />
</binding>
</webHttpBinding>


The problem is visible when I break on the encodedString piece and it doesn't match what I'm expecting. If I copy the entire string into another online image that generates images from base64 strings, it's not a valid image. At this point I'm stuck and haven't been able to determine why I can't read from dropzone.

Answer

For anyone else looking to configure a WCF service to catch dropzone images, be aware that dropzone sends multipart/form-data that looks like:

------WebKitFormBoundary
Content-Disposition: form-data; name="data"; filename="DSCF0001.JPG"
Content-Type: image/jpeg

<file bytes>
------WebKitFormBoundary--

There isn't a built-in way to parse this data that I found, however this blog post goes into more details and provides a codeplex MultipartParser class that worked perfectly for this scenario.

Simplified WCF code now looks like:

public string AddImageStream(Stream img)
    {
        MultipartParser parser = new MultipartParser(img);

        string encodedString = "";

        if (parser.Success)
        {
            // Save the file
            encodedString = SaveFile(parser.Filename, parser.ContentType, parser.FileContents);
        }

        return encodedString;
    }