lunedì 13 febbraio 2012

jquery asp.net mvc e chiamate cross domain

Pensavo fosse una cosa semplicissima.

Il progetto: chiamare una pagina nel dominio del motore di ricerca e ottenere le strutture messe in offerta in tempo reale.

La soluzione: creare un nuovo controllore, la relativa azione, configurare il routing in modo che la richiesta di un indirizzo corrisponda la restituzione di json completo di tutte le strutture.

Sembrava una cosa semplicissima il controller sfruttando la potenza del framework .Net:

[HttpGet]
        public JsonResult GetListaOfferte(int num = 0)
        {
            IEnumerable<ProdottoListinoViewModel> listaRisultati = _siteService.GetProdottoOffertaCatalogo();
            return Json(listaRisultati.Distinct(new ProdottoListinoViewModelComparer()).ToList().Take(num), JsonRequestBehavior.AllowGet);
        } 
Il passo successivo è stata la scrittura del javascript:


$.ajax({
url: "(..)/api/GetListaOfferte",
data: {num: "8"},
type: "GET", contentType: "application/json; charset=utf-8", success: function(response) {
alert(response);
}, dataType: "json"
});

Da questo punto in poi sono cominciati i guai. Il problema è che $.ajax subisce i limiti di sicurezza definiti dalla same-domain policy.

La soluzione è stata utilizzare JSONP e quindi implementare un action filter (grande .Net) e poi cambiare la chiamata ajax:


public class JsonpFilterAttribute : ActionFilterAttribute    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext == null)
                throw new ArgumentNullException("filterContext");
            
            string callback = filterContext.HttpContext.Request.QueryString["callback"];
            if (callback != null && callback.Length > 0)
            {
               
                JsonResult result = filterContext.Result as JsonResult;
                if (result == null)
                {
                    throw new InvalidOperationException("JsonpFilterAttribute must be applied only " +
                        "on controllers and actions that return a JsonResult object.");
                }
                filterContext.Result = new JsonpResult                {
                    ContentEncoding = result.ContentEncoding,
                    ContentType = result.ContentType,
                    Data = result.Data,
                    Callback = callback
                };
            }
        }
    }


aggiungere l'attributo [JsonpFilter] all'azione del controller.
E infine modificare la chiamata ajax:


$.getJSON(
"http://(...)/api/GetListaOfferte?callback=?",
{num: "8" },
function(data) {
alert(data);
});

Nessun commento: