¿Cómo puedo producir JSONP desde un servicio web ASP.NET para llamadas entre dominios?
jquery cross-domain (3)
En caso de que alguien esté buscando una muestra de cómo devolver JSONP
de la acción de la Web API
ASP.NET
:
// GET api/values
public JsonpResult Get()
{
var values = new string[] { "value1", "value2" };
return new JsonpResult(values);
}
JsonpResult
ayuda JsonpResult
encapsula el JsonpResult
JSONP
.
public class JsonpResult : JsonResult
{
object _data = null;
public JsonpResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext controllerContext)
{
if (controllerContext != null)
{
var response = controllerContext.HttpContext.Response;
var request = controllerContext.HttpContext.Request;
var callBackFunction = request["callback"];
if (string.IsNullOrEmpty(callBackFunction))
{
throw new Exception("Callback function name must be provided in the request!");
}
response.ContentType = "application/x-javascript";
if (_data != null)
{
var serializer = new JavaScriptSerializer();
response.Write(string.Format("{0}({1});", callBackFunction, serializer.Serialize(_data)));
}
}
}
}
He escrito un servicio web que devuelve JSON y he intentado llamarlo usando jQuery de esta manera:
$.ajax({
contentType: "application/json; charset=utf-8",
url: "http://examplewebsite.com/service.asmx/GetData",
data: { projectID: 1 },
dataType: "jsonp",
success: function () {alert("success");}
});
Sin embargo, el código nunca llama a la función de éxito, a pesar de que la llamada del servicio web tiene éxito cuando se observa el tráfico HTTP mediante Fiddler. Creo que esto se debe a que mi servicio web está devolviendo JSON sin formato en lugar de JSONP.
¿Cómo puedo producir JSONP como la respuesta de un método de servicio web .NET estándar como este:
[WebMethod(), ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public Project GetData(int projectID)
{
Project p = new Project();
p.Name = "foobar";
return p;
}
Gracias.
Gracias Nick, esa fue una excelente respuesta a un problema que al principio también tuve dificultades para encontrar en línea. Funcionó muy bien para mí también.
Quería asegurarme de que esta línea de publicación recibiera la atención que merece.
Solo quería agregar que utilicé el serializador integrado (System.Runtime.Serialization.Json) y también funcionó de maravilla.
List<orderHistory> orderHistory = null;
StringBuilder sb = new StringBuilder();
JavaScriptSerializer js = new JavaScriptSerializer();
sb.Append(callback + "(");
sb.Append(js.Serialize(orderHistory));
sb.Append(");");
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.Write(sb.ToString());
Context.Response.End();
OK, eventualmente lo he descubierto yo mismo. Como me resultó muy difícil encontrar una solución de trabajo completa en la web, he decidido documentar mi solución de trabajo aquí.
Una respuesta JSONP es solo una cadena JSON estándar envuelta en una llamada de función. ASP.NET no parece proporcionar ninguna forma de devolver la respuesta en este formato directamente, pero es muy simple hacerlo usted mismo. Sin embargo, sí tienes que anular el método predeterminado de codificación JSON.
A continuación se muestra un ejemplo de JSONP.
functionName({ name: ''value'';});
.. ahora este bit: { name: ''value'';}
es solo JSON estándar que cualquier serializador JSON le proporcionará, por lo que todo lo que tenemos que hacer es agregar el envoltorio de llamada a función. Desafortunadamente, hacerlo significa que tenemos que ''desenmarañar'' (o ignorar) la codificación JSON existente que se maneja de forma transparente por el marco cuando devuelve un objeto de la función de servicio web.
Esto se hace anulando completamente la respuesta de la función de servicio web escribiendo el JSONP en el flujo de salida (Respuesta) usando nuestro propio código. Esto es en realidad bastante sencillo y he incluido un ejemplo a continuación.
Puede usar el DataContractJsonSerializer incorporado (desde el espacio de nombres System.Runtime.Serialization.Json en ASP.NET 3.5+) o el serializador NewtonSoft JSON , y ambos ejemplos se muestran a continuación. Prefiero usar el NewtonSoft JSON (instalado desde nuget) en lugar del JSON incorporado, ya que me da más control y también puede dar salida a un JSON legible con formato para la depuración. ¡También es mucho más rápido en papel!
[WebMethod()]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetData(int projectID, string callback)
{
List<Video> videos = null;
// <code here to populate list on line above>
// Method 1: use built-in serializer:
StringBuilder sb = new StringBuilder();
JavaScriptSerializer js = new JavaScriptSerializer();
sb.Append(callback + "(");
sb.Append(js.Serialize(videos));
sb.Append(");");
// Method 2: NewtonSoft JSON serializer (delete as applicable)
// StringBuilder sb = new StringBuilder();
// sb.Append(callback + "(");
// sb.Append(JsonConvert.SerializeObject(videos, Formatting.Indented)); // indentation is just for ease of reading while testing
// sb.Append(");");
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.Write(sb.ToString());
Context.Response.End();
}
Este método puede luego ser llamado usando el siguiente código JQuery:
$.ajax({
crossDomain: true,
contentType: "application/json; charset=utf-8",
url: "http://examplewebsite.com/service.asmx/GetData",
data: { projectID: 1 }, // example of parameter being passed
dataType: "jsonp",
success: onDataReceived
});
function onDataReceived(data)
{
alert("Data received");
// Do your client side work here.
// ''data'' is an object containing the data sent from the web service
// Put a JS breakpoint on this line to explore the data object
}