0

I'm looking for an example of an ajax call for streaming data to a WCF service. I am always getting an error. Any help appreciated, or even links to blogs with a solution. This is my WCF service class

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Images : IImages
{
    string IImages.UploadImage(string fileKey, Stream imageStream)
    {
        using (var fileStream = File.Create(@"Images\" + fileKey))
        {
            imageStream.CopyTo(fileStream);
        }
        return "done";
    }
}

and my contract is

[OperationContract(Name = "UploadImage")]
[WebInvoke(UriTemplate = "?file_key={fileKey}", Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
string UploadImage(string fileKey, Stream imageStream);

I have web.config stream binding

<binding name="PublicStreamBinding"
        maxReceivedMessageSize="2000000000" transferMode="Streamed">
    <security mode="None" />
</binding> 

my ajax client call is like this

var data = '{"image":"' + uri + '"}'
$.ajax({
    url: GetServerUrl()+"images.svc/?file_key="+options.fileKey,
    type: "POST",
    contentType: "application/json",
    data: data,
    success: function (result) {
        console.log("SUCCESS");
    },
    error: function (jqXHR, textStatus, errorThrown) {
        console.log("error in transfer::" + jqXHR.responceText);
    }
});
Clinton Ward
  • 2,441
  • 1
  • 22
  • 26

2 Answers2

1

I can't comment on the server-side code, but client-side :

  • the data variable should be a plain javascript object, not a JSON representation
  • url shouldn't need the GetServerUrl() prefix; try a leading "/" instead
  • for a POST request it's more normal to include all parameters in the data object rather than tacking them onto the URL, which is the GET approach. It depends what the server-side code is set up to expect but as far as I can tell, it expects file_key to be in the POST.

You should end up with something like this :

var data = {
    image: uri,
    file_key: options.fileKey
};
$.ajax({
    url: "/images.svc/",//probably
    type: "POST",
    contentType: "application/json",
    data: data,
    success: function (result) {
        console.log("SUCCESS");
    },
    error: function (jqXHR, textStatus, errorThrown) {
        console.log("errror in transfer::" + jqXHR.responceText);
    }
});
Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • Thanks for the tips, I tried to have the data set up like you said but i get a message "errror in transfer::undefined". I should really spell error correctly, will fix my post. – Clinton Ward Dec 01 '12 at 16:41
  • You can see above the service is set up for a POST. Do you know how i can get a more maningful error message? – Clinton Ward Dec 01 '12 at 16:46
  • I rather like "errror" with three 'r's - it has a certain *je ne sait qqqouoi*. For a more meaningful error message, try exploring the two parameters `textStatus` and `errorThrown` passed to the error handler. – Beetroot-Beetroot Dec 01 '12 at 17:16
  • On that same point, c# should let you set HTTP response headers such that an application error stimulates an HTTP response error. That way (client-side), success will always end up in the success handler and errors of all types will end up in the error handler. Otherwise, you have to handle application errors in the success handler, which is messy. I have only ever needed to do this in PHP but the principles must be identical regardless of which server-side technology is used. – Beetroot-Beetroot Dec 01 '12 at 17:25
0

Install Fiddler ( www.telerik.com/fiddler ). Launch it. Make the web service call. Click on the record of the call in Fiddler. Click on the 'Raw' tabs for request and response. It will be enlightening and you will see exactly what is passed between server and client. Perhaps some addition WCF troubleshooting data as well in the response.

Also, don't forget to check your Application event log on the machine running the WCF service. You can also add a Global.asax to the WCF project (if its a web project) and put logging code in the Application_Error method. Something like this:

    protected void Application_Error(object sender, EventArgs e)
    {       
        Exception ex = Server.GetLastError();

        if (ex is ThreadAbortException)
        {
            // Nothing to do here. The thread abended.
        }
        else
        {
            activityMgr.Add(System.Reflection.MethodBase.GetCurrentMethod(), ex);
        }
    }
LarsK
  • 11
  • 2