Wie kann ich sauberes JSON von einem WCF-Dienst zurückgeben?

233

Ich versuche, JSON von einem WCF-Dienst zurückzugeben. Dieser Dienst gibt einfach einige Inhalte aus meiner Datenbank zurück. Ich kann die Daten bekommen. Ich bin jedoch besorgt über das Format meines JSON. Derzeit ist der zurückgegebene JSON wie folgt formatiert:

{"d":"[{\"Age\":35,\"FirstName\":\"Peyton\",\"LastName\":\"Manning\"},{\"Age\":31,\"FirstName\":\"Drew\",\"LastName\":\"Brees\"},{\"Age\":29,\"FirstName\":\"Tony\",\"LastName\":\"Romo\"}]"} 

In Wirklichkeit möchte ich, dass mein JSON so sauber wie möglich formatiert wird. Ich glaube (ich kann mich irren), dass dieselbe Sammlung von Ergebnissen, die in sauberem JSON dargestellt wird, so aussehen sollte:

[{
  "Age": 35,
  "FirstName": "Peyton",
  "LastName": "Manning"
}, {
  "Age": 31,
  "FirstName": "Drew",
  "LastName": "Brees"
}, {
  "Age": 29,
  "FirstName": "Tony",
  "LastName": "Romo"
}]

Ich habe keine Ahnung, woher das "d" kommt. Ich habe auch keine Ahnung, warum die Escape-Zeichen eingefügt werden. Meine Entität sieht wie folgt aus:

[DataContract]
public class Person
{
    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }

    [DataMember]
    public int Age { get; set; }

    public Person(string firstName, string lastName, int age)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
        this.Age = age;
    }
}

Der Dienst, der für die Rücksendung des Inhalts verantwortlich ist, ist definiert als:

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    public string GetResults()
    {
        List<Person> results = new List<Person>();
        results.Add(new Person("Peyton", "Manning", 35));
        results.Add(new Person("Drew", "Brees", 31));
        results.Add(new Person("Tony", "Romo", 29));

        // Serialize the results as JSON
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(results.GetType());
        MemoryStream memoryStream = new MemoryStream();
        serializer.WriteObject(memoryStream, results);

        // Return the results serialized as JSON
        string json = Encoding.Default.GetString(memoryStream.ToArray());
        return json;
    }
}

Wie kann ich "sauberes" JSON von einem WCF-Dienst zurückgeben? Danke dir!

user208662
quelle
SOAP sollte XML zurückgeben. Sie können einen REST-Endpunkt verwenden, um JSON zurückzugeben. Werfen
Akira Yamamoto
4
Übrigens, wenn jemand anderes darauf stößt und sich fragt, warum die Eigenschaft "d" vorhanden ist, kann eine JSON-Sicherheitsanfälligkeit behoben werden . Wenn Sie es entfernen, werden Sie wieder verwundbar.
Alex
4
@Alex - Diese Sicherheitsanfälligkeit hängt von der Neudefinition des Array-Objekts ab, was in modernen Browsern nicht mehr möglich ist. Siehe stackoverflow.com/questions/16289894/…
Cheeso
Das ist gut. :) Die Hälfte meiner Antwort ist jedoch immer noch wahr - sie war da, um diese Sicherheitsanfälligkeit zu beheben.
Alex

Antworten:

213

Ändern Sie den Rückgabetyp Ihrer GetResults in List<Person>.
Beseitigen Sie den Code, mit dem Sie die Liste in eine JSON-Zeichenfolge serialisieren - WCF erledigt dies automatisch für Sie.

Unter Verwendung Ihrer Definition für die Person-Klasse funktioniert dieser Code für mich:

public List<Person> GetPlayers()
{
    List<Person> players = new List<Person>();
    players.Add(new  Person { FirstName="Peyton", LastName="Manning", Age=35 } );
    players.Add(new  Person { FirstName="Drew", LastName="Brees", Age=31 } );
    players.Add(new  Person { FirstName="Brett", LastName="Favre", Age=58 } );

    return players;
}

Ergebnisse:

[{"Age":35,"FirstName":"Peyton","LastName":"Manning"},  
 {"Age":31,"FirstName":"Drew","LastName":"Brees"},  
 {"Age":58,"FirstName":"Brett","LastName":"Favre"}]

(Alles in einer Zeile)

Ich habe dieses Attribut auch für die Methode verwendet:

[WebInvoke(Method = "GET",
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "players")]

WebInvoke mit Method = "GET" ist dasselbe wie WebGet, aber da einige meiner Methoden POST sind, verwende ich alle WebInvoke aus Gründen der Konsistenz.

Das UriTemplate legt die URL fest, unter der die Methode verfügbar ist. Also kann ich ein GET machen http://myserver/myvdir/JsonService.svc/playersund es funktioniert einfach.

Schauen Sie sich auch IIRF oder einen anderen URL-Umschreiber an, um die .svc in der URI zu entfernen.

Cheeso
quelle
Cheeso - Ich habe diesen Ansatz ausprobiert, bevor ich diese Frage gestellt habe. Wenn ich diesen Ansatz verwende, wird die Fehlermeldung angezeigt, dass "Endpunkte mit 'UriTemplate' nicht mit 'System.ServiceModel.Description.WebScriptEnablingBehavior' verwendet werden können." Was mache ich falsch? Danke dir!
user208662
28
Verwenden Sie in Ihrer .config-Datei <webHttp /> anstelle von <webScriptEnablingBehavior />.
Cheeso
9
OK, ich habe <enableWebScript /> durch <webHttp /> ersetzt und das hat funktioniert.
MGOwen
3
MGowen - Zu Ihrer Information: Wenn Sie eine neue Frage stellen, ist es am besten, ... eine neue Frage zu öffnen, anstatt die Frage als Kommentar zu einer alten Antwort zu veröffentlichen.
Cheeso
5
Favre sieht, was Sie dort getan haben.
Ruffin
93

Wenn Sie einen netten JSON ohne Hardcodierung von Attributen in Ihre Serviceklassen wünschen,

Verwenden Sie <webHttp defaultOutgoingResponseFormat="Json"/>in Ihrer Verhaltenskonfiguration

JeremyWeir
quelle
8

Ich hatte das gleiche Problem und löste es, indem ich den BodyStyle-Attributwert in "WebMessageBodyStyle.Bare" änderte:

[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetProjectWithGeocodings/{projectId}")]
GeoCod_Project GetProjectWithGeocodings(string projectId);

Das zurückgegebene Objekt wird nicht mehr verpackt.

KhalilG
quelle
1

Wenn Sie die GET-Methode verwenden, muss dies der Vertrag sein.

[WebGet(UriTemplate = "/", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
List<User> Get();

Damit haben wir einen JSON ohne den Boot-Parameter

Aldo Flores @alduar http://alduar.blogspot.com

Alduar
quelle
1

Fügen Sie in Ihrer IServece.cs das folgende Tag hinzu: BodyStyle = WebMessageBodyStyle.Bare

 [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "Getperson/{id}")]

    List<personClass> Getperson(string id);
Osama Ibrahim
quelle
Können Sie auch erklären, warum BodyStyle das Ergebnis beeinflussen kann?
MBH