3

I made an AJAX call to send an image file to one of my web service (.asmx) methods. Everything's okay, but the problem is that the web service returns XML instead of JSON because I HAVE TO set 'contentType' to 'false', otherwise file can't be sent. (If I set contentType to application/json; charset=utf-8, it returns JSON but I can't do that because I'm sending a file.)

This is my JavaScript:

function setAvatar(imageFile, successCallback) {
var formData = new FormData();
formData.append("UploadedAvatar", imageFile);
$.ajax({
    type: "POST",
    url: "/Services/UserService.asmx/SetAvatar",
    contentType: false,
    processData: false,
    dataType: 'json',
    data: formData,
    success: function (result) {
        alert(result.d);
        alert(result.d.IsSuccessful);
        if (typeof successCallback === 'function')
            successCallback(result);
    }
});

And the web service method:

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Result SetAvatar()
{
    HttpPostedFile postedFile = HttpContext.Current.Request.Files["UploadedAvatar"];
    Image avatar = Image.FromStream(postedFile.InputStream, true, true);
    avatar = new Bitmap(avatar, new Size(150, 150));
    avatar.Save(Path.Combine(path, $"Avatar-Small.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);

    return new Result(true, Messages.AvatarSavedSuccessfully);
}
Nkosi
  • 191,971
  • 29
  • 311
  • 378
Arad
  • 1,815
  • 2
  • 19
  • 39
  • See my answer [here](https://stackoverflow.com/questions/49961146/webmethod-in-my-webservice-should-return-a-dataset-and-yet-returns-an-array/49961604#49961604). You're trying to return an object but it must be serialized first. You will probably be able to remove contentType after that and go with the default setting. – wazz Apr 29 '18 at 02:44
  • @wazz That didn't help me – Arad Apr 30 '18 at 09:57
  • See this https://stackoverflow.com/questions/42360139/asp-net-core-return-json-with-status-code, make sure you have `options.RespectBrowserAcceptHeader = true;`, so that the return type is based on the `Accept` header – Tarun Lalwani Apr 30 '18 at 12:13

3 Answers3

4

Set the Accept header when making the request to expect JSON

$.ajax({
    type: "POST",
    url: "/Services/UserService.asmx/SetAvatar",
    headers: { //SET ACCEPT HEADER
        Accept : "application/json; charset=utf-8",
    },  
    contentType: false,
    processData: false,
    dataType: 'json',
    data: formData,
    success: function (result) {
        alert(result.d);
        alert(result.d.IsSuccessful);
        if (typeof successCallback === 'function')
            successCallback(result);
    }
});

On the server side, using Json.Net you can serialize the result

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string SetAvatar() {
    HttpPostedFile postedFile = HttpContext.Current.Request.Files["UploadedAvatar"];
    Image avatar = Image.FromStream(postedFile.InputStream, true, true);
    avatar = new Bitmap(avatar, new Size(150, 150));
    avatar.Save(Path.Combine(path, $"Avatar-Small.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);

    var result = new Result(true, Messages.AvatarSavedSuccessfully);
    return JsonConvert.SerializeObject(result);
}

This should allow the response to be in the desired type

Nkosi
  • 191,971
  • 29
  • 311
  • 378
2

You need to update your .NET code and add options.RespectBrowserAcceptHeader = true

services
    .AddMvc(options => {
        options.RespectBrowserAcceptHeader = true;
    })
    //support application/xml
    .AddXmlDataContractSerializerFormatters()
    //support application/json
    .AddJsonOptions(options => {
        // Force Camel Case to JSON
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    });

The dataType: 'json' will automatically add the Accept header as below

"accept":"application/json, text/javascript, */*; q=0.01"

If you specifically want just application/json, then you need to add below to your ajax options

headers: {
  Accept : "application/json; charset=utf-8"
}
Tarun Lalwani
  • 124,930
  • 8
  • 149
  • 214
0

After beating my head against the wall for many days, I finally figured out the solution which belongs to Ajay, here.

While nothing else has helped me, I used this and it worked perfectly:

  1. Change the return type of your method to void.

  2. And then instead of writing the return statement in your method, you need to do this to return a value:

    Context.Response.ContentType = "application/json; charset=utf-8";
    Context.Response.Write(new JavaScriptSerializer().Serialize(new YourData()));
    
  3. After that you can easily get the result using the success event of the Ajax call:

    success: function (result) {
        alert(result.Property); // Note: Don't use result.d here
    }
    
Arad
  • 1,815
  • 2
  • 19
  • 39