2009-04-17 12 views
69

लौटने पर मैं डोमेन पर कुछ JSON वापस लौटने की सोच रहा हूं और मैं समझता हूं कि ऐसा करने का तरीका शुद्ध JSON की बजाय JSONP के माध्यम से है। मैं एएसपीनेट एमवीसी का उपयोग कर रहा हूं, इसलिए मैं सिर्फ JSONResult प्रकार को विस्तारित करने के बारे में सोच रहा था और उसके बाद नियंत्रक को विस्तारित करता था ताकि यह एक जेसनपी विधि भी कार्यान्वित किया जा सके। क्या यह इसके बारे में जाने का सबसे अच्छा तरीका है या क्या एक्शन रिसेट में बनाया गया है जो बेहतर हो सकता है?एएसपीनेट एमवीसी JSONP

संपादित करें: मैं आगे बढ़ गया और ऐसा किया।

public class JsonpResult : System.Web.Mvc.JsonResult 
    { 
     public override void ExecuteResult(ControllerContext context) 
     { 
      if (context == null) 
      { 
       throw new ArgumentNullException("context"); 
      } 

      HttpResponseBase response = context.HttpContext.Response; 

      if (!String.IsNullOrEmpty(ContentType)) 
      { 
       response.ContentType = ContentType; 
      } 
      else 
      { 
       response.ContentType = "application/javascript"; 
      } 
      if (ContentEncoding != null) 
      { 
       response.ContentEncoding = ContentEncoding; 
      } 
      if (Data != null) 
      { 
       // The JavaScriptSerializer type was marked as obsolete prior to .NET Framework 3.5 SP1 
#pragma warning disable 0618 
       HttpRequestBase request = context.HttpContext.Request; 

       JavaScriptSerializer serializer = new JavaScriptSerializer(); 
       response.Write(request.Params["jsoncallback"] + "(" + serializer.Serialize(Data) + ")"); 
#pragma warning restore 0618 
      } 
     } 
    } 

है और यह भी अपने सभी नियंत्रकों के एक सुपर क्लास करने के तरीकों की एक जोड़ी:

protected internal JsonpResult Jsonp(object data) 
     { 
      return Jsonp(data, null /* contentType */); 
     } 

     protected internal JsonpResult Jsonp(object data, string contentType) 
     { 
      return Jsonp(data, contentType, null); 
     } 

     protected internal virtual JsonpResult Jsonp(object data, string contentType, Encoding contentEncoding) 
     { 
      return new JsonpResult 
      { 
       Data = data, 
       ContentType = contentType, 
       ContentEncoding = contentEncoding 
      }; 
     } 

वर्क्स एक आकर्षण की तरह बस संदर्भ खातिर मैं एक नया परिणाम गयी।

+0

धन्यवाद! बस हमारी परियोजना में इसे लागू किया! :) –

+3

अच्छा! लेकिन JSONP को एप्लिकेशन/जावास्क्रिप्ट के रूप में कार्य किया जाना चाहिए http://stackoverflow.com/questions/111302/best-content-type-to-serve-jsonp –

+0

यह भी देखें http://support.github.com/discussions/api/18 -content-type-should-applicationjavascript-for-jsonp-request http://stackapps.com/questions/1668/wrong-content-type-in-jsonp-calls –

उत्तर

13

जेसनपी() विधियों के साथ मेरे नियंत्रकों को उपclass करने की बजाय, मैं विस्तार विधि मार्ग चला गया क्योंकि यह मुझे एक स्पर्श क्लीनर लगता है। JsonpResult के बारे में अच्छी बात यह है कि आप इसे उसी तरह से जांच सकते हैं जैसे आप JsonResult करेंगे।

मैंने किया:

public static class JsonResultExtensions 
{ 
    public static JsonpResult ToJsonp(this JsonResult json) 
    { 
     return new JsonpResult { ContentEncoding = json.ContentEncoding, ContentType = json.ContentType, Data = json.Data, JsonRequestBehavior = json.JsonRequestBehavior}; 
    } 
} 

इस तरह से आप सभी विभिन्न jsonp() भार के बनाने के बारे में चिंता करने की सिर्फ एक jsonp एक करने के लिए अपने JsonResult परिवर्तित नहीं है।

+2

जेसनपीआरएसल्ट क्लास क्या है? – Chookoos

+0

क्या आप इसे कॉल का उदाहरण दे सकते हैं? –

+2

अन्य टिप्पणीकारों के लिए, स्पष्ट होने के लिए, लापरवाही ओपी से कोड का निर्माण कर रहा है। – ruffin

-2

समाधान ऊपर काम करने का एक अच्छा तरीका है, लेकिन यह एक तरीका है कि एक JsonResult रिटर्न आप तरीकों कि अपनी खुद की परिणाम प्रकार वापसी लिखना चाहिए के बजाय परिणाम के एक नए प्रकार के साथ extendend किया जाना चाहिए

public JsonPResult testMethod() { 
    // use the other guys code to write a method that returns something 
} 

public class JsonPResult : JsonResult 
{ 
    public FileUploadJsonResult(JsonResult data) { 
     this.Data = data; 
    }  

    public override void ExecuteResult(ControllerContext context) 
    { 
     this.ContentType = "text/html"; 
     context.HttpContext.Response.Write("<textarea>"); 
     base.ExecuteResult(context); 
     context.HttpContext.Response.Write("</textarea>"); 
    } 
} 
0

उत्तेजना और रंजू वी द्वारा संदर्भित लेख दोनों बहुत उपयोगी थे और स्थिति स्पष्ट हो गई।

हालांकि, मुझे ऑनलाइन मिले एमवीसी कोड के संदर्भ में विस्तार, उप-वर्गीकरण का उपयोग करने के बारे में अपने सिर को खरोंच कर दिया गया था।

दो मुख्य बिंदु है कि मुझे बाहर पकड़ा हुई:

  1. कोड मैं ActionResult से ली गई थी, लेकिन ExecuteResult में वहाँ या तो XML या JSON वापस जाने के लिए कुछ कोड था।
  2. मैंने तब जेनरिक्स आधारित एक्शन रिसेट बनाया था, यह सुनिश्चित करने के लिए कि उसी निष्पादन के परिणामस्वरूप मेरे द्वारा लौटाए गए डेटा के प्रकार से स्वतंत्र रूप से उपयोग किया गया था।

तो, दोनों को मिलाकर - मुझे जेएसओएनपी वापस करने के लिए तंत्र जोड़ने के लिए और एक्सटेंशन या उप-वर्गीकरण की आवश्यकता नहीं थी, बस मेरे मौजूदा निष्पादन परिवर्तनों को बदलें।

मुझे क्या परेशान किया गया था कि वास्तव में मैं ExsonuteResult को दोबारा कोड किए बिना, JsonResult को प्राप्त करने या विस्तार करने का एक तरीका ढूंढ रहा था। चूंकि JSONP प्रभावी रूप से एक JSON स्ट्रिंग है जो उपसर्ग & प्रत्यय के साथ एक अपशिष्ट लग रहा था। हालांकि अंडरलिंग ExecuteResult respone.write का उपयोग करता है - इसलिए बदलने का सबसे सुरक्षित तरीका ExecuteResults को फिर से कोड करना है जो विभिन्न पोस्टिंग द्वारा प्रदान की जाती है!

यदि यह उपयोगी होगा तो मैं कुछ कोड पोस्ट कर सकता हूं, लेकिन इस धागे में पहले से ही बहुत सारे कोड हैं।

15

यहाँ, एक सरल उपाय है अगर आप jQuery का उपयोग कर एक कार्रवाई फिल्टर

क्लाइंट साइड कोड को परिभाषित नहीं करना चाहती:

$.ajax("http://www.myserver.com/Home/JsonpCall", { dataType: "jsonp" }).done(function (result) {}); 

MVC नियंत्रक कार्रवाई। क्वेरी स्ट्रिंग के साथ प्रदान किए गए कॉलबैक फ़ंक्शन को निष्पादित करने वाले जावास्क्रिप्ट कोड के साथ सामग्री परिणाम देता है। प्रतिक्रिया के लिए जावास्क्रिप्ट एमआईएमई प्रकार भी सेट करता है।

public ContentResult JsonpCall(string callback) 
{ 
     return Content(String.Format("{0}({1});", 
      callback, 
      new JavaScriptSerializer().Serialize(new { a = 1 })),  
      "application/javascript"); 
} 
10

Ranju's blog post (उर्फ "इस ब्लॉग पोस्ट मैंने पाया") उत्कृष्ट है, और पढ़ने यह इतना है कि अपने नियंत्रक एक ही डोमेन JSON और क्रॉस-डोमेन JSONP अनुरोधों में सुंदर ढंग से संभाल कर सकते हैं आप नीचे दिए गए समाधान को आगे बढ़ाने के लिए अनुमति देगा अतिरिक्त कोड [कार्रवाई में] के बिना एक ही नियंत्रक कार्रवाई।

भले ही, "मुझे कोड दें" प्रकारों के लिए, यहां ब्लॉग है, यदि ब्लॉग फिर से गायब हो जाता है। (नई/गैर-ब्लॉग कोड स्निपेट है)

अपने नियंत्रक में:

[AllowCrossSiteJson] 
public ActionResult JsonpTime(string callback) 
{ 
    string msg = DateTime.UtcNow.ToString("o"); 
    return new JsonpResult 
    { 
     Data = (new 
     { 
      time = msg 
     }) 
    }; 
} 

JsonpResult this excellent blog post पर पाया:

/// <summary> 
/// Renders result as JSON and also wraps the JSON in a call 
/// to the callback function specified in "JsonpResult.Callback". 
/// http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx 
/// </summary> 
public class JsonpResult : JsonResult 
{ 
    /// <summary> 
    /// Gets or sets the javascript callback function that is 
    /// to be invoked in the resulting script output. 
    /// </summary> 
    /// <value>The callback function name.</value> 
    public string Callback { get; set; } 

    /// <summary> 
    /// Enables processing of the result of an action method by a 
    /// custom type that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>. 
    /// </summary> 
    /// <param name="context">The context within which the 
    /// result is executed.</param> 
    public override void ExecuteResult(ControllerContext context) 
    { 
     if (context == null) 
      throw new ArgumentNullException("context"); 

     HttpResponseBase response = context.HttpContext.Response; 
     if (!String.IsNullOrEmpty(ContentType)) 
      response.ContentType = ContentType; 
     else 
      response.ContentType = "application/javascript"; 

     if (ContentEncoding != null) 
      response.ContentEncoding = ContentEncoding; 

     if (Callback == null || Callback.Length == 0) 
      Callback = context.HttpContext.Request.QueryString["callback"]; 

     if (Data != null) 
     { 
      // The JavaScriptSerializer type was marked as obsolete 
      // prior to .NET Framework 3.5 SP1 
#pragma warning disable 0618 
      JavaScriptSerializer serializer = new JavaScriptSerializer(); 
      string ser = serializer.Serialize(Data); 
      response.Write(Callback + "(" + ser + ");"); 
#pragma warning restore 0618 
     } 
    } 
} 

नोट:comments to the OP by @Ranju and others पर के बाद, मैं यह पता चला कि यह एक समुदाय विकी के रूप में रंजू के ब्लॉग पोस्ट से "न्यूनतम न्यूनतम" कार्यात्मक कोड पोस्ट करने लायक था। हालांकि यह कहना सुरक्षित है कि रंजू ने उपरोक्त और अन्य कोड को अपने ब्लॉग पर स्वतंत्र रूप से इस्तेमाल करने के लिए जोड़ा, लेकिन मैं यहां उनके शब्दों की प्रतिलिपि बनाने वाला नहीं हूं।

+1

धन्यवाद @ruffin! इन दिनों में से एक ऐसा करने का मतलब था। इसे करने के लिए धन्यवाद! :) – Raj

0
 using System; 
     using System.Collections.Generic; 
     using System.Linq; 
     using System.Web; 
     using System.Web.Mvc; 
     using System.Web.Script.Serialization; 

     namespace Template.Web.Helpers 
     { 
      public class JsonpResult : JsonResult 
      { 
       public JsonpResult(string callbackName) 
       { 
        CallbackName = callbackName; 
       } 

       public JsonpResult() 
        : this("jsoncallback") 
       { 
       } 

       public string CallbackName { get; set; } 

       public override void ExecuteResult(ControllerContext context) 
       { 
        if (context == null) 
        { 
         throw new ArgumentNullException("context"); 
        } 

        var request = context.HttpContext.Request; 
        var response = context.HttpContext.Response; 

        string jsoncallback = ((context.RouteData.Values[CallbackName] as string) ?? request[CallbackName]) ?? CallbackName; 

        if (!string.IsNullOrEmpty(jsoncallback)) 
        { 
         if (string.IsNullOrEmpty(base.ContentType)) 
         { 
          base.ContentType = "application/x-javascript"; 
         } 
         response.Write(string.Format("{0}(", jsoncallback)); 
        } 

        base.ExecuteResult(context); 

        if (!string.IsNullOrEmpty(jsoncallback)) 
        { 
         response.Write(")"); 
        } 
       } 
      } 

      public static class ControllerExtensions 
      { 
       public static JsonpResult Jsonp(this Controller controller, object data, string callbackName = "callback") 
       { 
        return new JsonpResult(callbackName) 
        { 
         Data = data, 
         JsonRequestBehavior = JsonRequestBehavior.AllowGet 
        }; 
       } 

       public static T DeserializeObject<T>(this Controller controller, string key) where T : class 
       { 
        var value = controller.HttpContext.Request.QueryString.Get(key); 
        if (string.IsNullOrEmpty(value)) 
        { 
         return null; 
        } 
        JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); 
        return javaScriptSerializer.Deserialize<T>(value); 
       } 
      } 
     } 

//Example of using the Jsonp function:: 
    // 1- 
    public JsonResult Read() 
      { 
       IEnumerable<User> result = context.All();   

       return this.Jsonp(result); 
      } 
    //2- 
    public JsonResult Update() 
      { 
       var models = this.DeserializeObject<IEnumerable<User>>("models"); 
       if (models != null) 
       { 
        Update(models); //Update properties & save change in database 
       } 
       return this.Jsonp(models); 
      } 
+2

क्या आप कृपया केवल एक कोड-केवल उत्तर नहीं, बल्कि अधिक जानकारी प्रदान कर सकते हैं? – Thomas