I was looking around the web recently searching for a quick fix to sending Ajax requests back and forth between different servers, and a specific fix for ASP.NET MVC using JQuery's getJSON() method. This is for a service that I would like to make for http://hurl.me. After some research it was apparent that I was going to have to get in their and dirty my hands. Here is what I determined.
- Cross Domain (i.e. http://example.com requesting an object from http://hurl.me) is not a "trusted" technique
- Web services (*.ascx) aren't suiting my needs, I want to go custom
- Possible through JQuery using a ?callback=?&append other information here
- One or two responses on the web doing similar stuff in other languages (Python, PHP), Sending back the callback variable like this callback + "(" + JSON Object + ")"
So I determined first that it was possible and that there were no sites currently boasting about this in ASP.NET MVC (I don't write my own stuff if I can find a solution that already works). This could be very helpful for RESTful services when you want to use several web servers to carry out extensive solutions that meet specific requirements.
Some other things that I was concerned about were testing. It isn't that difficult, as I have the two environments, but I did not want to go back and forth thrashing through my web application, since I am plugging it in and not doing it in a separate solution.
I started with DotNet Reflector, seeing how they are using the current Json() available to controllers. This was an interesting dive, surprisingly simple. Some things to note here are that I would like to eventually just extend Json(), though my time is extremely pressed.
After some Reflector Awakening, I set out to put this into play. First thing I did was create a new class (right click the folder or project -> new class). I named this file JsonExtension (remember my future plans of extending Json() instead of the current way I do it here). I also followed along with the steps here.
Here is my code for the cross domain solution (Custom to My Solution: Hurl2.Controllers, you may want to put it in the same namespace as your controllers):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web;
using System.Web.Script.Serialization;
namespace Hurl2.Controllers
{
public class JsonServer : ActionResult
{
public Object Data { get; set; }
public string CallBack { get; set; }
public JsonServer() { }
public JsonServer(Object obj, string CallBack)
{
this.CallBack = CallBack;
this.Data = obj;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException();
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "application/json";
if (this.Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
response.Write(
String.Format(
"{1}({0})",
serializer.Serialize(this.Data),
this.CallBack)
);
}
}
}
}
This is how I use it. Notice that I am very close to the current use of Json(), except I have a new JsonServer(params) object instance for now. This is a small example for proof of concept. You will not get the same results if you try calling this function at Hurl. Below is using regular ASP.NET MVC Conventions for routing in this case. The route is /Url/IsAvailable?query string. To make the call cross domain it would be {domain name}/Url/IsAvailable?callback=?&other query strings.
public ActionResult IsAvailable(string shortUrl)
{
var callback = Request.QueryString["callback"];
if (String.IsNullOrEmpty(callback))
return Json(new { isAvailable = ShortUrl.isAvailable(shortUrl).ToString() });
else
{
return new JsonServer(new { isAvailable = ShortUrl.isAvailable(shortUrl).ToString() }, callback);
}
}
From the page where I call this, my JQuery looks like this. The cross domain is trivial in this case, since it works both ways. I could (above) take the first if statement out but I would like the option of providing the callback or not.
$.getJSON("/Url/IsAvailable?callback=?&shorturl=" + encodeURIComponent($('input[name=ShortUrl]').val()),processShortUrl);
In this article, we cover plugging in cross domain compatible AJAX for services that don't reside on the server. This is a server side way to solve the cross domain issue if you want to provide services to others. This is the "easiest fix" approach. It is probably a good idea to do some refactoring where you see that being beneficial. If you have improvements or have overridden Json(string callback, object data), then feel free to let me know so I can save time. 70 hours a week + programming 3 or 4 sites on the side really kills the spare time!
Enjoy.