Cross-domain JSONP with jQuery call step-by-step guide

I’ve been banging my head all day to accomplish this, it’s like a puzzle.. but since i get it to work i thought i could write this post for you and myself.

What we want to accomplish?

Simple way to communicate cross-domain with ASMX .NET 3.5 Web Service

How can we do it?

1. Implement a web service method like the following

   [ScriptService]
   public class JSONP_EndPoint : System.Web.Services.WebService
   {
       [WebMethod]
       [ScriptMethod(UseHttpGet = true,ResponseFormat = ResponseFormat.Json)]
       public string Sum(string x,string y)
       {
           return x + y;
       }
   }

2. Add New class library with a name ContentTypeHttpModule

The reason for this is no matter how you specify the content-type of your ajax call ASP.NET send the request with Content-Type text/xml; charset=utf-8 this is security feature explained here by ScottGu 

3. Add the following code to your Class (Code by Jason i just did a simple modification)

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

namespace ContentTypeHttpModule
{
    public class ContentTypeHttpModule : IHttpModule
    {
        private const string JSON_CONTENT_TYPE = "application/json; charset=utf-8";

        #region IHttpModule Members
        public void Dispose()
        {
        }

        public void Init(HttpApplication app)
        {
            app.BeginRequest += OnBeginRequest;
            app.ReleaseRequestState += OnReleaseRequestState;
        }
        #endregion

        public void OnBeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpRequest resquest = app.Request;
            if (!resquest.Url.AbsolutePath.Contains("JSONP-EndPoint.asmx")) return;

            if (string.IsNullOrEmpty(app.Context.Request.ContentType))
            {
                app.Context.Request.ContentType = JSON_CONTENT_TYPE;
            }
        }

        public void OnReleaseRequestState(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpResponse response = app.Response;
            if (app.Context.Request.ContentType != JSON_CONTENT_TYPE) return;

            response.Filter = new JsonResponseFilter(response.Filter);
        }
    }

    public class JsonResponseFilter : Stream
    {
        private readonly Stream _responseStream;
        private long _position;

        public JsonResponseFilter(Stream responseStream)
        {
            _responseStream = responseStream;
        }

        public override bool CanRead { get { return true; } }

        public override bool CanSeek { get { return true; } }

        public override bool CanWrite { get { return true; } }

        public override long Length { get { return 0; } }

        public override long Position { get { return _position; } set { _position = value; } }

        public override void Write(byte[] buffer, int offset, int count)
        {
            string strBuffer = Encoding.UTF8.GetString(buffer, offset, count);
            strBuffer = AppendJsonpCallback(strBuffer, HttpContext.Current.Request);
            byte[] data = Encoding.UTF8.GetBytes(strBuffer);
            _responseStream.Write(data, 0, data.Length);
        }

        private string AppendJsonpCallback(string strBuffer, HttpRequest request)
        {
            return request.Params["callback"] +"(" + strBuffer + ");";
        }

        public override void Close()
        {
            _responseStream.Close();
        }

        public override void Flush()
        {
            _responseStream.Flush();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _responseStream.Seek(offset, origin);
        }

        public override void SetLength(long length)
        {
            _responseStream.SetLength(length);
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _responseStream.Read(buffer, offset, count);
        }
    }
}

4. Register the HttpModule in the service project

4.1 Add referance to the HttpModule assembly to the service project

4.2 Add this code to web.config to register the module

<add name="ContentTypeHttpModule"

                    type="ContentTypeHttpModule.ContentTypeHttpModule, ContentTypeHttpModule" />

This goes under system.web / httpmodules section

5. Add a web project for testing the application

5.1 add the following libs

jquery-1.3.1.js

json2.js

5.2 add new script file caller.js

function test() {
    $.ajax({ url: "http://localhost:1690/JSONP-EndPoint.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!");
        }
    });
}
5.3 Add referances to jquery-1.3.1.js and json2.js
5.4 Add Default.aspx page with input button that has onclick=”return test();”

6. Remarks

6.1 I use the JSON.stringify function to serialize the string data parameters.

6.2 .d is a security features on ASP.NET 3.5

Download the code

63 thoughts on “Cross-domain JSONP with jQuery call step-by-step guide”

  1. The article is great! There is one major issue with using buffer – if the response is buffered then each part (buffer) is wrapped with the callback method and that results in an incorrect javascript and response. However it’s possible to turn off buffering by adding response.BufferOutput = false; in OnReleaseRequestState. Of course this may have some impact on performance.

  2. 5 stars to you!

    You had the simplest solution to this problem! Thank you so much!

    Best of all, the solution still works with ASP.NET 2.0 w/ AJAX Extensions (sans the .d in the Javascript call)

  3. I’ve tried this and it works great in IE.
    However, it doesn’t work in any other browser for me.
    Did I do something wrong?
    Do I need json2.js anyway?

  4. @Adel:

    I tried to connect to a Web service which return a line of text and I want to show that text in a lebel.
    Here is the .asmx code:

    [ScriptService]
    public class Events : WebService
    {
    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public string HelloWorld()
    {
    return “Hello World”;
    }
    }

    Here is my jQuery code:

    var options = {
    url: “http://ws.someweb.com/events.asmx/HelloWorld”,
    data: {},
    dataType: “jsonp”,
    success: function(msg) { $(“#message”).html(msg.d); },
    error: function(msg) { alert(msg); }
    }

    $.ajax(options);

    This works just fine in IE, but not in the other browsers I mentioned earlier.

    Any idea please?

  5. This is weird. I tried running your project and it works just fine in all browsers. But it somehow doesn’t work for me in firefox, opera, and chrome. T-T

  6. OK, I finally figured it out.
    Using

  7. Thanks for sharing this, I am aspnet developer and i am implementing above scenario in dot net nuke i have done all the settings but still i am unable to call the service any idea?

  8. Great article, thx.

    Do you know why this isn’t working with VB based webservice?

    I used ContentTypeHttpModule.dll as is (so it stays as C#) and pretty sure didn’t make any mistake on client side (whenever i switch url to C# based webservice it works) so the only part left is below.

    Thank you for your time and attention.

    Best

    ‘—–

    Imports System.Web
    Imports System.Web.Services
    Imports System.Web.Services.Protocols

    ‘ To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    _
    _
    _
    _
    Public Class JSONP_EndPoint
    Inherits System.Web.Services.WebService

    _
    _
    Public Function Sum(ByVal x As String) As String
    Return x & ” _echoed!”
    End Function

    End Class

  9. To make it work, I had to add (like JakeC):
    —————–

    ————————-

    But – the web service only returns json (formatted server-side) in xml tags. Anyone found a way around this?

  10. My bad – I didn’t edit this line of the ContentTypeHttpModule:
    ———————
    if (!resquest.Url.AbsolutePath.Contains(“JSONP-EndPoint.asmx”)) return;
    ———————
    I just replaced “JSONP-EndPoint.asmx” with my webservice name. I then commented out the following from the web.config:
    —————–

    ————————-

    Now it works – thanks for the help!

  11. Hi

    I have tried to use this solution however my website is on a different server I cannot invoke the webservice from there is there any reason why its failing…

    Thank you for your help

    Sal

  12. Hi Sal,

    The idea for using JSONP is to make a cross-domain communication so having your website on a different server is a requirement :) please provide me with more information in order to help you and understand the problem more.

    Adel.

  13. Hi Adel,

    Firstly thank you for your quick response.
    What I have done is used your project and I have published both the webservice and the web application within your project to my server. When I navigate to the default page and click on the ‘invoke’ button I get the response back so I know that it is working fine and that the webservice has been published correctly.

    However my html page is on a different server so what I have done is copied the caller.js, jquery-1.3.1.js and the json2.js files on to my other server and I have referenced them within my html file, however it seems like I don’t get a response back, nothing is returned.

    I really appreciate your help, could you please tell me what I am doing wrong.

    Thank you.

    Sal

  14. Hi Adel

    I have come to the conclusion that the issue is not the consuming of the web service but erm the actual json output. I am trying to convert the a datatable in to json output format using your project how would that be possible. Could you please point me in the right direction.

    Thank you.

    Sal

  15. You can try JSON.Stringfy() method that returns a json string, however i may help me identify the problem if you share a subset of the output returned.

    Make sure you have used the Http Module to alter the request from XML to JSON.

    Thanks.
    Adel.

  16. Hi Adel,

    I think I figured out what the issue was when I was converting the datatable to json it was putting double quotes around the values where as in order for javascript parse it, it requires single quotes around it. I now need to convert your project in to a VB project do you have a sample of your project in VB??

    Sal

  17. Hi Adel,

    Thank you for your help I have successfully been able to use your project to create my cross domain application. However there is one more issue that I was wondering whether you would be able to help me with. What is the best way to authenticate a user I have an Asp.net webservice I can use integrated windows authentication or forms authentication. The webservice is microsoft based but the client application is not.

    My question is does JSONP support SOAP headers and how secure is it to send username and password information across the usual Ajax Jsonp route, would MD5 make it secure enough?

    Any input from you would be great!

    Thanks Again! your project has helped me out a lot.

    Sal

  18. Very happy that you got it to work, regarding Windows Auth, i don’t think that will work with non-windows clients that is from conceptual point of view, for JSONP supporting SOAP header i too don’t think so.

    MD5 hash will be secure for most cases but depend of your type of application and the sensitivity of the data that is transmitted, you can also rely on SSL to tunnel the username and password hash that would make it allot harder to break.

    but still you need to think about your data and application domain.

    Thanks and let me know if i can help.
    Adel.

  19. Thanks for this…

    I applied this into my development machine and it worked ok…
    when I tried the same code from a test machine I am getting
    “Web Service method name is not valid”

    The client application which try to access the web service is Classic ASP
    the Web service application is ASP.NET 2.0

    Any advice?

  20. I think this is the most detailed resource on the topic – thank you. But it did not work for me as the server returns 500 error whenever I try to assign the contenttype:
    app.Context.Request.ContentType = JSON_CONTENT_TYPE;

    Here is my situation:
    ASP.NET 3.5, asmx web service, IIS 6.
    I tried your code as httpmodule but was getting 500 error. Whenever I comment out the contenttype assignment line, it works but returns the result wrapped as XML string – and that’s exactly what I am trying to avoid. I then removed the httpmodule and did the assignment of contenttype in Global.asax in BeginRequest – same 500 error.
    BTW, I cannot see the reason for the error as it likely happens before my web service gets control. Even when I return immediately from the webservice, without any processing, the error has already occurred.
    I tried to access this from jquery as well as straight from the browser – same thing.
    I would appreciate any advice on this.
    Thank you.

  21. Hi

    I tried your code in my web service and html page, but unfortunately its not working in my case. May be i am doing some mistake. I am sending you my code, please help me regarding this issue. I have included the Handler that was required.
    This is my Method in web service:

    _
    _
    Public Function HelloWorld() As String
    Return “Hello World”
    End Function

    My JSON Request.

    $(document).ready(function() {
    $.ajax({
    url: “http://www.flymrt.com/BookingEngine/MRTJSON2.asmx/AgentLoginJSON?callback=?”,
    data: {x:”test”},
    dataType: “jsonp”,
    contentType: ‘application/json’,
    success: function(msg){
    alert(‘aya’);
    },
    error: function(msg)
    {
    alert(‘error’);
    }
    });
    });

    Thanks and your help would be appreciated.

  22. Hi

    I tried your code in my web service and html page, but unfortunately its not working in my case. May be i am doing some mistake. I am sending you my code, please help me regarding this issue. I have included the Handler that was required.
    This is my Method in web service:

    _
    _
    Public Function AgentsLogin() As String
    Return “Hello World”
    End Function

    My JSON Request.

    $(document).ready(function() {
    $.ajax({
    url: “http://www.flymrt.com/BookingEngine/MRTJSON2.asmx/AgentLoginJSON?callback=?”,
    data: {x:”test”},
    dataType: “jsonp”,
    contentType: ‘application/json’,
    success: function(msg){
    alert(‘aya’);
    },
    error: function(msg)
    {
    alert(‘error’);
    }
    });
    });

    Thanks and your help would be appreciated.

  23. Hello Adel,

    I amk stuck with JSONP. I am trying to use access a webservice on a different domain and here is my code:

    var count = 2;
    var fieldNames = jQuery.makeArray(["affiliateID", "encryptedOrderID"]);
    var fieldValues = jQuery.makeArray(["AID", "OID"]);

    var webMethod = “http://xx.xx.com/opslistener/Service.asmx?op=OPSListener”;
    var parameters = “{‘fieldCount’ : ” + count + “, ‘fields’: ” + fieldNames + “, ‘values’: ” + fieldValues + “}”;
    jQuery.ajax({
    type: “GET”,
    url: webMethod,
    contentType: “application/json”,
    dataType: “JSONP”,
    data: parameters,
    success: function(response) {
    jQuery(“#WebServiceResult”).append(response);
    }

    });

    Nothing is happening in the webservice and the “response” I am getting is the Test form that we get when we type the url in the address bar.

    This is kind of very important for me. Quick help is totally appreciated.

    Thanks Much in advance!

  24. Been pulling my hair out over this all day. Was able to get my webservice to allow GET request and starting getting this error:

    Error: missing ; before statement

    Found your site and also read the link from Elegant Code listed above. I created the custom httphandler, remembering to change the endpoint.asmx, and added the module to my web.config. I am still getting the error:

    Error: missing ; before statement

    How can I check to see that the custom handler is doing what it is supposed to do. It would appear that it is not.

    Here is my jquery statement:

    $.ajax({
    url: “http://aresdev/newsimages.asmx/GetImagesByPrefix?jsoncallback=?”,
    data: { strPrefix: prefix },
    dataType: “jsonp”,
    success: function(json) {
    alert(json.d);
    }
    });

    Thanks in advance,
    Jason

  25. I have webservice hosted on other subdomain e.g s1.abc.com/WebServices/LikeTest.asmx/test

    LikeTest.asmx it my webservice and test is function.

    No I want to call that webservice in other subdomain named impex.abc.com

    So,please help me.I tried many things but in vain.It’s not running well.

    Urgently needed help.

  26. Just a tip:
    if you’re using IIS7 instead of 6, the code in web.config should be placed at system.webServer/modules instead of system.web/httpModules.

  27. Hi Adel,

    I have used your code in my website. But i am getting nothing. I am calling a cross domain web service from a html page using jquery ajax function. I followed all your steps but could not find the desired output.when i run the web service i am getting an error in web.config as -
    Parser Error Message: Could not load type ‘ContentTypeHttpModule.ContentTypeHttpModule’ from assembly ‘ContentTypeHttpModule’

  28. Hi Adel,

    I resolved the ContentTypeHttpModule registration error. as i am using IIS7 integrated mode the registration bit is different in web.config. Anyway, but still i am not able to get the desired output. Now, i am getting a weird error. “A runtime Syntax Error”. And it is not able to debug the error. Any inputs?

  29. Hi,
    When using IIS 7.5 and VS2010 don’t forget to change the Application Pool settings as follows:
    Manage Pipeline mode: Classic
    .Net version: 2.0
    Otherwise you will get out put as XML and not JSONP

  30. Really Superb dude. Thanks a lot.. I was searhing for this solution from past 3 days.. finally i got it.. hip hip hurray :)

  31. Tried for while to get this example working. Can get JavaScript to call the web service (setup with debugging and steps into service) but always falls into the error function of the ajax call with a code 200, success????

    Code identical as example really:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using Newtonsoft.Json;
    using System.Web.Script.Services;
    namespace PE
    {
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // 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 HHTransfer : System.Web.Services.WebService
    {
    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public object GetData()
    {
    return JsonConvert.SerializeObject(DateTime.Now);
    }
    }
    }

    function test() {

    $.ajax({ url: “http://localhost/HHTransfer/HHTransfer.asmx/GetData”,
    data: {},
    dataType: “jsonp”,
    success: function (json)
    {
    debugger;
    alert(json.d);
    },
    error: function (e)
    {
    debugger;
    alert(“Hit error fn!”);
    }
    });
    }

    Also add items to web.config for service

    “wont work without this”

    Have also tried explicit return types from the service makes no difference.

    any ideas???

  32. interestingly the data is actually in the responseText of the error in raw XML form

    e.g.

    responseText: ”
    “2012-05-19T18:27:03.4423071+01:00″”
    status: 200
    statusText: “OK”

  33. Hi great article first of all but i need one more thing, how can we handle session management. with the module Session object in the HTTPCONTEXT always null. How can we define a variable in the session as Session["k"] = 3. i saw we can do this kind of definition in another article but in here we can not. how can we add this property to this code?
    thanks

  34. For everyone still having problems you’ll need to modify the HttpModule class.

    There is a line of code in there that does a compare on the asmx file used. All you have to do is change that and it will work.

    Ex.
    if (!resquest.Url.AbsolutePath.Contains(“JSONP-EndPoint.asmx”)) return;

  35. Hi there,

    JSONP call returns error.Below is the error messeage.

    But When I set data type as json, It works fine in IE but not in FF & Chrome. What am I missing?.

    {“readyState”:4,”status”:200,”statusText”:”success”}parsererrorError: jQuery182025999106633830127_1353740618424 was not called.

  36. Here is my Code

    $.ajax({
    url: locationUrl + ‘/AdmissionRequest.asmx/getProgramsJD’,
    type: ‘GET’,
    dataType: dtype,
    data: “{}”,
    async: false,
    cache: false,
    contentType: ‘application/json; charset=utf-8′,
    success: function (data) {
    source.localdata = $.parseJSON(data.d);
    },
    error: function (xhr, status, error) {
    alert(JSON.stringify(xhr) + status + error);
    }
    });

  37. hi scenario is i have c# website application live
    that is data driven from sql server database. i need to allow other websites(not mine) on different domains query the database using an ajax call i suppose to list a table of records on their page. would this work around of using jsonp be the correct option?

  38. hi scenario is i have c# website application live
    that is data driven from sql server database. i need to allow other websites(not mine) on different domains query the database using an ajax call i suppose to list a table of records on their page. would this work around of using jsonp be the correct option?

  39. - it currently work at localhost with

    url: “localhost:1690/JSONP-EndPoint.asmx/Sum”

    - but I get a trouble when i publish on the real server. it doesn’t work with

    url: “abc.com/JSONP-EndPoint.asmx/Sum”

    thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>