it-swarm.com.de

So serialisieren Sie die __type-Eigenschaft für JSON-Objekte nicht

Jedes Objekt, das ich von einem WebMethod eines ScriptService zurückliefe, wird in ein JSON-Objekt mit den Daten in einer Eigenschaft namens d eingeschlossen. Kein Problem. Ich möchte jedoch nicht, dass die zusätzliche __type-Eigenschaft an den Client geliefert wird, da ich sie manuell mit jQuery erledige.

Ist es möglich?

60
Robert

Nun, es ist lange her, seit du gefragt hast. Ich habe festgestellt, dass wenn ich den Standardkonstruktor meiner Klasse mache, dass meine Webmethode etwas anderes als public zurückgibt, der Teil __type: ClassName nicht serialisiert wird.

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

39
John Morrison

Johns Lösung hat für mich nicht funktioniert, da der Typ, den ich zurückbringe, in einer separaten DLL liegt. Ich habe volle Kontrolle über das DLL =, aber ich kann meinen Rückgabetyp nicht erstellen, wenn der Konstruktor intern ist.

Ich habe mich gefragt, ob der Rückgabetyp, der ein öffentlicher Typ in einer Bibliothek ist, vielleicht sogar die Ursache ist. Ich habe viel Ajax gemacht und habe diesen noch nicht gesehen. 

Schnelltests:

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

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

Seltsamerweise bekomme ich __type nicht mit einem generischen Rückgabetyp:

[WebMethod]
public static WebMethodReturn<IEnumerable<FleetObserverLiteAddOns.VehicleAddOnAccountStatus>> GetAccountCredits()

Die solution für mich bestand jedoch darin, meinen Rückgabetyp in der DLL zu belassen, aber den WebMethod-Rückgabetyp in Objekt zu ändern, d. H.

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

anstatt

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

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

Die einfachste Methode, die ich zum Entfernen der Typhinweise entdeckt habe, besteht darin, das Verhalten des Endpunkts von enableWebScript in webHttp zu ändern.

    <behavior name="MapData.MapDataServiceAspNetAjaxBehavior">
      <webHttp />
    </behavior>

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

16
Jonathan Sayce

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

JsConfig.ExcludeTypeInfo = true;

Diese Funktionalität wurde automatisch in v2.28 hinzugefügt, der obige Code verhindert jedoch die Serialisierung. Sie können dieses Verhalten auch mit Type ändern:

JsConfig<Type>.ExcludeTypeInfo = true;
10
Brett Veenstra

Übergeben Sie null für den JavaScriptTypeResolver, und der Typ __ wird nicht serialisiert

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

Ich glaube, ich habe die Ursache des mysteriös erscheinenden "__type" eingegrenzt!

Hier ist ein Beispiel, in dem Sie das Problem erneut 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üsselteil!

Nur weil MyMethodA () in derselben .asmx-Datei vorhanden ist, verwendet und die Klasse Cat als Parameter .... Der __-Typ wird der JSON hinzugefügt, die vom Aufruf der anderen Methode zurückgegeben wird: MyMethodB ().

Obwohl es unterschiedliche Methoden sind !!

Meine Theorie lautet wie folgt: 

  1. Wenn Sie Web-Services wie dieses schreiben, verbindet Microsoft-Code automatisch das JSON-Serialisierungs-/Deserialisierungs-Verhalten für Sie, da Sie die richtigen Attribute wie [WebMethod] und [ScriptService] verwendet haben.
  2. Wenn dieser automatisch-magische Microsoft-Code ausgeführt wird, findet er eine Methode, die die Cat-Klasse als Parameter verwendet.
  3. Es stellt dar ... oh ... ok .... gut, da ich ein Cat-Objekt von JSON erhalten werde .... also ... wenn ich je / ein Cat-Objekt als JSON von einer beliebigen Methode in zurückschicke Die aktuelle Web-Service-Klasse ... Ich gebe ihr eine __type -Eigenschaft, so dass es später leicht zu identifizieren ist, wenn Sie wieder zu C # deserialisiert werden.
  4. Nyah-hahahaha ...

Wichtige Mitnahmebestätigung

Sie können vermeiden, dass die Eigenschaft __type in Ihrem generierten JSON-Objekt angezeigt wird, indem Sie vermeiden, die betreffende Klasse (in meinem Fall Cat) als Parameter für Ihre WebMethods in Ihrem Web-Service zu verwenden. Versuchen Sie einfach, im obigen Code MyMethodA () so zu ändern, dass der Parameter Cat entfernt wird. Dies bewirkt, dass die Eigenschaft __type nicht generiert wird.

2
ClearCloud8

Zusätzlich zu den Empfehlungen von John Morrison zum internen oder geschützten internen Konstruktor in Ihrer DataContract-Klasse, die erstaunlich gut für Web-Services und die Mehrheit von WCF funktioniert, müssen Sie möglicherweise eine zusätzliche Änderung in Ihrer web.config vornehmen file . Anstelle des <enableWebScript/>-Elements verwenden Sie <webHttp/> für Ihre Endpunkt-Eigenschaften, zB:

<endpointBehaviors>
  <behavior name="MyServiceEndpoint">
    <webHttp/>
  </behavior>
</endpointBehaviors>
2
Art Kg

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

2
Mironline

Etwas spät zum Thread aber hier geht es.

Wir hatten das gleiche Problem, als die Eigenschaft, die zum json-String hinzugefügt wurde, eine Liste <T> war. Was wir getan haben, war eine weitere Eigenschaft hinzuzufügen, die aus einem Array von T bestand.

Vor.

[DataMember]
public List<Person> People { get; set; }

Nach dem.

public List<Person> People { get; set; }

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

Dies ist zwar keine ideale Lösung, aber der Trick.

1
Michael

Das sollte es lösen.

In der privaten SerializeValue-Methode von JavaScriptSerializer in System.WebExtensions.dll wird der Typ __ einem internen Wörterbuch hinzugefügt, falls er aufgelöst 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<string, object> 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 ermittelt werden kann, wird die Serialisierung fortgesetzt, der Typ wird jedoch ignoriert. Die gute Nachricht ist, dass, da anonyme Typen getType () erben und die zurückgegebenen Namen vom Compiler dynamisch generiert werden, TypeResolver für ResolveTypeId Null zurückgibt und das Attribut "__type" anschließend ignoriert wird.

Ich habe auch John Morrisons Rat für den internen Konstruktor befolgt, nur für den Fall, dass ich mit dieser Methode immer noch __type-Eigenschaften in meiner JSON-Antwort erhielt.

//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<Foo> foos = new List<Foo>();
        rtnFoos.Add( new Foo(){
            Bar=99
        }};

        var rtn = from g in foos.AsEnumerable()
                   select g;

        return rtn;
    }
}

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

0
Laramie

Verwenden Sie nicht das Attribut [Serializable]. 

Folgendes sollte es einfach tun

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

0
sean

Hier ist ein Weg, um das zu umgehen

    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public void Status()
    {
        MyObject myObject = new MyObject(); // Your class here
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(myObject);

        HttpContext.Current.Response.Write(json);
    }
0
Liran BarNiv

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

a) Schützen Sie den parameterlosen Konstruktor 

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

Wenn Sie die Klasse niemals als Parameter übergeben müssen, können Sie den Konstruktor als "protected internal" 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 jedoch die Klasse 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 in Json übergebenen Daten in Ihrer Klasse nicht deserialisiert werden können ).

Dies war mein Problem, also musste ich eine Kombination aus (a) und (b) verwenden: Schützen Sie den parameterlosen Konstruktor und erstellen Sie eine Dummy-abgeleitete Klasse, die ausschließlich für Parameter für Webmethoden verwendet wird. 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 aufgenommen werden muss, verwendet stattdessen MyClassForParams:

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

Zusätzlich zu @seans Antwort auf die Verwendung von JavaScriptSerializer.

Wenn Sie JavaScriptSerializer verwenden und den ResponseFormat = WebMessageFormat.Json der Methode markieren, weist die resultierende Antwort die doppelte JSON-Codierung auf. Wenn die resultierende Antwort string ist, werden sie in zwei Anführungszeichen gesetzt.

Um dies zu vermeiden, verwenden Sie die Lösung aus diese hervorragende Antwort , um den Inhaltstyp als JSON (Überschreiben) zu definieren und das binäre Ergebnis der JavaScriptSerializer zu streamen.

Das Codebeispiel aus der genannten Antwort:

public Stream GetCurrentCart()
{
    //Code ommited
    var j = new { Content = response.Content, Display=response.Display,
                  SubTotal=response.SubTotal};
    var s = new JavaScriptSerializer();
    string jsonClient = s.Serialize(j);
    WebOperationContext.Current.OutgoingResponse.ContentType =
        "application/json; charset=utf-8";
    return new MemoryStream(Encoding.UTF8.GetBytes(jsonClient));
}

JavaScriptSerializer befindet sich im System.Web.Script.Serialization-Namespace von System.Web.Extensions.dll, auf den standardmäßig nicht verwiesen wird.

0
Alex Pandrea