Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cross domain call with jQuery jsonp to ASP.NET web service

My problem is known issue and discussed here and here. But even after reading and implementing the suggested solutions i am unable to make this work.

The problem: the web service returning xml insted of json:

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">"Now i am getting jsop string""2nd param"</string>

Now lets break the code into sections:

THE REMOTE SERVER (IIS 7.0, .NET 4):
web.config:

<?xml version="1.0"?>
<configuration>
        <system.webServer>
            <modules>
                <add name="JsonHttpModule.JsonHttpModule" type="JsonHttpModule"/>
            </modules>
        </system.webServer>
    <system.web.extensions>
        <scripting>
            <webServices>
                <jsonSerialization maxJsonLength="102400"/>
            </webServices>
        </scripting>
    </system.web.extensions>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
        <customErrors mode="Off"/>
        <webServices>
            <protocols>
                <add name="HttpGet"/>
                <add name="HttpPost"/>
            </protocols>
        </webServices>
    </system.web>
</configuration>


the web service:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using JsonHttpModule;
/// <summary>
/// Summary description for JSONP_EndPoint
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
[System.Web.Script.Services.ScriptService]
public class MyService : System.Web.Services.WebService {
    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public string Sum(string x, string y)
    {
        return x + y;
    }

}


the HttpModule class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;

/// <summary>
/// Summary description for ContentTypeHttpModule
/// </summary>
namespace JsonHttpModule
{
    public class JsonHttpModule : IHttpModule
    {
        private const string JSON_CONTENT_TYPE = "application/json; charset=utf-8";

        public void Dispose()
        {
        }
        public void Init(HttpApplication app)
        {
            app.BeginRequest += OnBeginRequest;
            app.EndRequest += new EventHandler(OnEndRequest);
        }
        public void OnBeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpRequest request = app.Request;
            //Make sure we only apply to our Web Service
            if (request.Url.AbsolutePath.ToLower().Contains("MyService.asmx"))
            {
                if (string.IsNullOrEmpty(app.Context.Request.ContentType))
                {
                    app.Context.Request.ContentType = JSON_CONTENT_TYPE;
                }
                app.Context.Response.Write(app.Context.Request.Params["callback"] + "(");
            }
        }
        void OnEndRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpRequest request = app.Request;
            if (request.Url.AbsolutePath.ToLower().Contains("MyService.asmx"))
            {
                app.Context.Response.Write(")");
            }
        }
    }
}

CLIENT SIDE (localhost):

<script>
    $(function () {
        $('#btn_test').click(function () {
            $.ajax({ url: "http://tonofweb.com/MyService.asmx/Sum",
                data: { x: JSON.stringify("Now i am getting jsop string"), y: JSON.stringify("2nd param") },
                dataType: "jsonp",
                success: function (json) {
                    alert(json.d);
                },
                error: function () {
                    alert("Hit error fn!");
                }
            });
    });
});
</script>
    <input id="btn_test" type="button" value="POST" />

so what am i doing wrong here? you can test it yourselves it's a live web service. Thank you for your help.

like image 731
baba-dev Avatar asked Jan 16 '12 18:01

baba-dev


People also ask

Can JSONP execute JavaScript?

It was proposed by Bob Ippolito in 2005. JSONP enables sharing of data bypassing same-origin policy, which disallows running JavaScript code to read media DOM elements or XMLHttpRequest data fetched from outside the page's originating site.

What is the one reason to avoid using JSONP in a web application?

JSONP is just a script include that allows you to use a callback. You should however be aware of Cross-site request forgery (CSRF). As long as you control the script and the server, JSONP isn't anymore insecure than a script include. Unless you have a JSONP-service that returns sensitive data to logged in users.

Can JSONP be used with Ajax?

JSONP allows you to sidestep the same-origin policy and to some extent make cross-domain Ajax calls. It's not a silver bullet, and it certainly has its issues, but in some cases it can prove invaluable when fetching data from a different origin.

What is JSONP callback?

JSONP is an informal protocol that allows you to make cross-domain calls by producing script tags on the current page and awaiting a response to a callback handler you provide.


1 Answers

It seems all the configuration and attributes are in place for the web service to return JSON but I did notice in your jQuery request, you are not specifying the content type of the data you are passing in. I have added it to the code below:

$.ajax({
  url: "http://tonofweb.com/MyService.asmx/Sum",
  contentType: "application/json; charset=utf-8",
  data: { x: JSON.stringify("1"), y: JSON.stringify("2") },
  dataType: "jsonp",
  success: function (json) {
    alert(json.d);
  },
  error: function () {
    alert("Hit error fn!");
  }
});

Notice I added contentType: "application/json; charset=utf-8", to the request settings.

I have tested this code by browsing to http://tonofweb.com (which returns a 403 at the moment), including jQuery using the jQuerify bookmarklet, and then running the code from your question first (without the contentType), and then the code I posted above (with the contentType).

Here are the responses from the Network tab in the Chrome Developer Tools:

Without contentType:

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">"Now i am getting jsop string""2nd param"</string>

With contentType:

{"d":"12"}

So the second one at least results in JSON being returned from the server. So all else being equal, I'd say add the contentType.

See here for an explanation of the requirements to return JSON:

ASMX and JSON – Common mistakes and misconceptions

The HTTP request must declare a content-type of application/json. This informs the ScriptService that it will receive its parameters as JSON and that it should respond in kind.

Now you still have another problem, and that is that the request, upon completion, calls the error function. If you change dataType: "jsonp" to dataType: "json" it will call the success function. So something about your implementation of the callback wrapper is wrong, because jQuery can't handle the response as JSONP.

Now I'm not seeing the callback wrapped in the response either, for JSONP, the response should be something like:

jQuery17106476630216930062_1326752446188({"d":"12"})

I notice you are linking to this post about how to do a JSONP response from a web service, but you are not following the advice: you don't use Response.Filter, instead you use Response.Write.

like image 78
Michiel van Oosterhout Avatar answered Sep 30 '22 11:09

Michiel van Oosterhout