2013-01-08 22 views
20

Pisałem usługa, która zwraca JSON i próbowałem to nazwać jQuery tak:Jak mogę utworzyć JSONP z usługi sieciowej ASP.NET dla wywołań między domenami?

$.ajax({ 
    contentType: "application/json; charset=utf-8", 
    url: "http://examplewebsite.com/service.asmx/GetData", 
    data: { projectID: 1 }, 
    dataType: "jsonp", 
    success: function() {alert("success");} 
}); 

Jednak kod nie wywołuje funkcję sukces, pomimo wezwania Zestawienie może zakończyć się sukcesem, gdy patrząc na Ruch HTTP za pomocą Fiddlera. Myślę, że dzieje się tak dlatego, że moja usługa sieciowa zwraca surowy JSON zamiast JSONP.

Jak mogę produkować jsonp jako odpowiedź od standardowej metody .NET Zestawienie tak:

[WebMethod(), ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)] 
public Project GetData(int projectID) 
{ 
    Project p = new Project(); 
    p.Name = "foobar"; 
    return p; 
} 

Dzięki.

+0

Mam tylko zrobić z ASP.Net Web API opartego na to: http://stackoverflow.com/a/9422178/585552 może dać Ci kilka pomysłów ... – Greg

+0

spróbuj dodać 'Response .AddHeader ("Access-Control-Allow-Origin", "*") 'w ciele metody internetowej – Icarus

Odpowiedz

43

OK, w końcu sam to wymyśliłem. Ponieważ ciężko mi było znaleźć kompletne działające rozwiązanie w Internecie, zdecydowałem się tutaj udokumentować moje działające rozwiązanie.

Odpowiedź JSONP to tylko standardowy ciąg JSON zawinięty w wywołanie funkcji. ASP.NET nie wydaje się oferować żadnego sposobu zwracania odpowiedzi w tym formacie bezpośrednio, ale bardzo łatwo jest to zrobić samodzielnie. Musisz jednak zastąpić domyślną metodę kodowania JSON.

Poniżej znajduje się przykład JSONP.

functionName({ name: 'value';});

..now ten bit: { name: 'value';} jest tylko standard JSON, że każdy serializer JSON da się, więc wszystko co musisz zrobić, to przyczepność na opakowaniu wywołania funkcji. Niestety, oznacza to, że musimy "odpiąć" (lub ominąć) istniejące kodowanie JSON, które jest obsługiwane w sposób przezroczysty przez strukturę, gdy zwracamy obiekt z funkcji usługi sieciowej.

Dokonuje się tego przez całkowite zastąpienie odpowiedzi z funkcji usługi sieciowej przez napisanie JSONP do strumienia wyjściowego (Response) przy użyciu naszego własnego kodu. Jest to całkiem proste i dodałem przykład poniżej.

Można użyć wbudowanego DataContractJsonSerializer (z obszaru nazw System.Runtime.Serialization.Json w ASP.NET 3.5+) lub serializera NewtonSoft JSON, a oba przykłady przedstawiono poniżej. Wolę korzystać z NewtonSoft JSON (zainstalowanego z nugetu) niż z wbudowanego serializatora JSON, ponieważ uważam, że daje on większą kontrolę, a także może wysyłać dobrze sformatowany czytelny dla użytkownika JSON do debugowania. Jest także znacznie szybszy na papierze!

[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(); 
} 

Ta metoda może być nazywane przy użyciu następującego kodu 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 
} 
+4

Uratowałeś mój dzień :) – Exor

+0

Nie wysłałeś' callbacku' w żądaniu ajax. Jak mogłeś go otrzymać w metodzie C#? – Sami

+1

@Sami - jest automatycznie dodawany przez JQuery – NickG

3

Dzięki Nick, który był doskonały odpowiedź na problem, że ja też miałem problem ze znalezieniem w pierwszym Online. Sprawdziło się również dla mnie.

Chciałem się upewnić, że ta linia postu ma uwagę, na którą zasługuje.

Po prostu chciałem dodać, że użyłem wbudowanego serializera (System.Runtime.Serialization.Json) i działało to jak i urok.

 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(); 
0

W przypadku, gdy ktoś patrzy na próby, jak powrócić JSONP z ASP.NETWeb API działania:

// GET api/values 
public JsonpResult Get() 
{ 
    var values = new string[] { "value1", "value2" }; 
    return new JsonpResult(values); 
} 

JsonpResult klasa pomocnika enkapsulacji opakowanie 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))); 
      } 
     } 
    } 
}