Wie wird die __type-Eigenschaft für JSON-Objekte nicht serialisiert?

Jedes Objekt, das ich von einem WebMethod eines ScriptService wird in ein JSON-Objekt mit den Daten in einer Eigenschaft namens d eingepackt. Das ist ok. Aber ich möchte nicht, dass die zusätzliche Eigenschaft __type an den Client __type , da ich manuelle Verarbeitung mit jQuery mache.

Ist es möglich?

Nun, es ist lange her, seit du gefragt hast. Ich fand, dass, wenn ich den Standardkonstruktor meiner class mache, dass mein webmethod irgendetwas anderes als öffentliches zurückgibt, es den __type: ClassName Teil nicht serialisiert.

Möglicherweise möchten Sie Ihren Standardkonstruktor als protected internal ClassName(){} deklarieren

Johns Lösung funktionierte nicht für mich, da der Typ, den ich zurückgebe, in einer separaten DLL ist. Ich habe volle Kontrolle über diese DLL, aber ich kann meinen Rückgabetyp nicht konstruieren, wenn der Konstruktor intern ist.

Ich fragte mich, ob der Rückgabetyp, der ein öffentlicher Typ in einer Bibliothek ist, sogar die Ursache sein könnte – ich habe viel Ajax gemacht und diesen bisher nicht gesehen.

Schnelltests:

  • Die Rückgabetypdeklaration wurde vorübergehend in App_Code verschoben. Immer noch __type serialisiert.

  • Dito und verwendet den geschützten internen Konstruktor per JM. Das hat funktioniert (also bekommt er eine Stimme).

Seltsamerweise bekomme ich __type mit einem generischen Rückgabetyp:

 [WebMethod] public static WebMethodReturn> GetAccountCredits() 

Die Lösung für mich war jedoch, meinen Rückgabetyp in der DLL zu belassen, aber den Rückgabetyp WebMethod in Objekt zu ändern , d

 [WebMethod] public static object ApplyCredits(int addonid, int[] vehicleIds) 

Anstatt von

 [WebMethod] public static WebMethodReturn ApplyCredits(int addonid, int[] vehicleIds) 

Ich habe einige dieser Vorschläge mit einem .NET 4 WCF-Dienst versucht, und sie scheinen nicht zu funktionieren – die JSON-Antwort enthält immer noch __type.

Der einfachste Weg, den Typhinweis zu entfernen, ist das Ändern des Endpunktverhaltens von enableWebScript in webHttp.

     

Das standardmäßige enableWebScript-Verhalten ist erforderlich, wenn Sie einen ASP.NET AJAX-Client verwenden. Wenn Sie jedoch JSON mit JavaScript oder jQuery bearbeiten, ist das Verhalten von webHttp wahrscheinlich die bessere Wahl.

Wenn Sie ServiceStack.Text JSON Serializer verwenden, müssen Sie nur:

 JsConfig.ExcludeTypeInfo = true; 

Diese functionalität wurde automatisch in Version 2.28 hinzugefügt, aber der obige Code hält das aus der Serialisierung heraus. Sie können dieses Verhalten auch ändern, indem Sie Type eingeben:

 JsConfig.ExcludeTypeInfo = true; 

Übergeben Sie NULL für den JavaScriptTypeResolver, und der __type wird nicht serialisiert

 JavaScriptSerializer serializer = new JavaScriptSerializer(null); string json = serializer.Serialize(foo); 

Ich bin mir nicht sicher, ob das eine gute Lösung ist, aber wenn Sie die Json.net- Bibliothek verwenden, können Sie einige Eigenschaften ignorieren, indem Sie das [JsonIgnore] -Attribut hinzufügen.

Ich denke, ich habe die Ursache des mysteriösen “__type” eingegrenzt!

Hier ist ein Beispiel, in dem Sie das Problem neu erstellen können.

 [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class Test : System.Web.Services.WebService { public class Cat { public String HairType { get; set; } public int MeowVolume { get; set; } public String Name { get; set; } } [WebMethod] public String MyMethodA(Cat cat) { return "return value does not matter"; } [WebMethod] public Cat MyMethodB(String someParam) { return new Cat() { HairType = "Short", MeowVolume = 13, Name = "Felix the Cat" }; } } 

Hier ist der Schlüssel!

Einfach weil MyMethodA () in der gleichen .asmx-Datei existiert und die class Cat als Parameter verwendet … wird der __type zum JSON hinzugefügt, der vom Aufruf der anderen Methode zurückgegeben wird: MyMethodB ().

Obwohl sie verschiedene Methoden sind !!

Meine Theorie ist wie folgt:

  1. Beim Schreiben von Webdiensten wie diesem hängt der Microsoft-Code automatisch das JSON-Serialisierungs- / Deserialisierungsverhalten für Sie ein, da Sie die richtigen Attribute wie [WebMethod] und [ScriptService] verwendet haben.
  2. Wenn dieser auto-magische Microsoft-Code ausgeführt wird, findet er eine Methode, die die Cat-class als Parameter akzeptiert.
  3. Es stellt sich heraus … oh … ok … nun, da ich ein Cat-Objekt von JSON empfangen werde …. daher … wenn ich jemals ein Cat-Objekt als JSON von einer beliebigen Methode im aktuellen Web-Service zurückgeben werde class … Ich gebe ihr eine Eigenschaft __type, so dass sie später beim Deserialisieren in C # leicht zu identifizieren ist.
  4. Nyah-hahahaha …

Wichtiger Take-Away Hinweis

Sie können vermeiden, dass die __type-Eigenschaft in Ihrem generierten JSON angezeigt wird, indem Sie verhindern, dass die fragliche class (in meinem Fall Cat) als Parameter für einen Ihrer WebMethods in Ihrem Webdienst übernommen wird. Versuchen Sie also im obigen Code, MyMethodA () zu ändern, um den Cat-Parameter zu entfernen. Dies führt dazu, dass die Eigenschaft __type nicht generiert wird.

Zusätzlich zu John Morrisons Ratschlag zu internem oder geschütztem internem Konstruktor in Ihrer DataContract-class, der erstaunlich gut für Web-Services und den Großteil von WCF funktioniert, müssen Sie möglicherweise eine zusätzliche Änderung in Ihrer Datei web.config vornehmen. anstelle des -Elements für Ihre , zB:

      

Ein bisschen spät zum Thread aber hier geht es.

Wir hatten das gleiche Problem, wenn die der JSON-Zeichenfolge hinzugefügte Eigenschaft eine List war. Was wir getan haben, war eine weitere Eigenschaft, die eine Anordnung von T, etwas wie.

Vor.

 [DataMember] public List People { get; set; } 

Nach.

 public List People { get; set; } [DataMember(Name = "People")] public Person[] Persons { get { return People.ToArray(); } private set { } } 

Obwohl es keine ideale Lösung ist, macht es den Trick.

Verwenden Sie nicht das Attribut [Serializable].

Folgendes sollte es einfach tun

JavaScriptSerializer ser = new JavaScriptSerializer (); Zeichenfolge json = ser.Serialize (objectClass);

Dies sollte es lösen.

In der privaten SerializeValue-Methode von JavaScriptSerializer in System.WebExtensions.dll wird der __type zu einem internen Wörterbuch hinzugefügt, wenn es aufgetriggers werden kann.

Vom Reflektor:

 private void SerializeValue(object o, StringBuilder sb, int depth, Hashtable objectsInUse) { if (++depth > this._recursionLimit) { throw new ArgumentException(AtlasWeb.JSON_DepthLimitExceeded); } JavaScriptConverter converter = null; if ((o != null) && this.ConverterExistsForType(o.GetType(), out converter)) { IDictionary dictionary = converter.Serialize(o, this); if (this.TypeResolver != null) { string str = this.TypeResolver.ResolveTypeId(o.GetType()); if (str != null) { dictionary["__type"] = str; } } sb.Append(this.Serialize(dictionary)); } else { this.SerializeValueInternal(o, sb, depth, objectsInUse); } } 

Wenn der Typ nicht bestimmt werden kann, wird die Serialisierung fortgesetzt, aber der Typ wird ignoriert. Die gute Nachricht ist, dass, da anonyme Typen getType () erben und die zurückgegebenen Namen dynamisch vom Compiler generiert werden, der TypeResolver null für ResolveTypeId zurückgibt und das Attribut “__type” anschließend ignoriert wird.

Ich habe auch John Morrisons Ratschlag mit dem internen Konstruktor für den Fall genommen, obwohl ich nur diese Methode nutzte, bekam ich immer noch __type-Eigenschaften in meiner JSON-Antwort.

 //Given the following class [XmlType("T")] public class Foo { internal Foo() { } [XmlAttribute("p")] public uint Bar { get; set; } } [WebService(Namespace = "http://me.com/10/8")] [System.ComponentModel.ToolboxItem(false)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class MyService : System.Web.Services.WebService { //Return Anonymous Type to omit the __type property from JSON serialization [WebMethod(EnableSession = true)] [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json, XmlSerializeString = false)] public object GetFoo(int pageId) { //Kludge, returning an anonymois type using link, prevents returning the _type attribute. List foos = new List(); rtnFoos.Add( new Foo(){ Bar=99 }}; var rtn = from g in foos.AsEnumerable() select g; return rtn; } } 

Hinweis: Ich verwende einen geerbten JSON-Typkonverter, der die XML-Serialisierungsattribute aus serialisierten Typen liest, um den JSON weiter zu komprimieren. Mit Dank an CodeJournal . Klappt wunderbar.

Meine 2 Cent, jedoch spät am Tag: Wie andere bereits erwähnt haben, scheint es zwei Möglichkeiten zu geben, die Eigenschaft “__type” zu verhindern:

a) Schützen Sie den parameterlosen Konstruktor

b) Vermeiden Sie, die class als Parameter an eine Webmethode zu übergeben

Wenn Sie die class nie als Parameter übergeben müssen, können Sie den Konstruktor als “intern geschützt” definieren. Wenn Sie ein leeres Objekt erstellen müssen, fügen Sie eine Factory-Methode oder einen anderen Konstruktor mit einem Dummy-Parameter hinzu.

Wenn Sie die class jedoch als Parameter an eine Webmethode übergeben müssen, werden Sie feststellen, dass dies nicht funktioniert, wenn der parameterlose Konstruktor geschützt ist (der Ajax-Aufruf schlägt fehl, vermutlich weil die übergebenen Json-Daten nicht in Ihre class deserialisiert werden können) ).

Dies war mein Problem, daher musste ich eine Kombination aus (a) und (b) verwenden: Schütze den parameterlosen Konstruktor und erstelle eine Dummy-abgeleitete class, die ausschließlich für Parameter zu Webmethoden verwendet werden soll. Z.B:

 public class MyClass { protected internal MyClass() { } public MyClass(Object someParameter) { } ... } // Use this class when we need to pass a JSON object into a web method public class MyClassForParams : MyClass { public MyClassForParams() : base() { } } 

Jede Webmethode, die in MyClass ausgeführt werden muss, verwendet stattdessen MyClassForParams:

 [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] public MyClass DoSomething(MyClassForParams someObject) { // Do something with someObject ... // Maybe return a MyClass object ... } 

Ich habe das Deklarieren des Standardkonstruktors getriggers. ClassName internal () {} Siehe auch die Antwort von John Morrison

Dies ist ein bisschen ein Hack, aber das funktionierte für mich (mit C #):

 s = (JSON string with "__type":"clsname", attributes) string match = "\"__type\":\"([^\\\"]|\\.)*\","; RegEx regex = new Regex(match, RegexOptions.Singleline); string cleaned = regex.Replace(s, ""); 

functioniert sowohl mit [DataContract] als auch mit [DataContract(Namespace="")]