Comment renvoyer du JSON propre à partir d'un service WCF?

233

J'essaie de renvoyer du JSON à partir d'un service WCF. Ce service renvoie simplement du contenu de ma base de données. Je peux obtenir les données. Cependant, je suis préoccupé par le format de mon JSON. Actuellement, le JSON qui est retourné est formaté comme ceci:

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

En réalité, j'aimerais que mon JSON soit formaté le plus proprement possible. Je crois (je peux me tromper) que la même collection de résultats, représentée en JSON propre, devrait ressembler à ceci:

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

Je n'ai aucune idée d'où vient le «d». Je ne sais pas non plus pourquoi les caractères d'échappement sont insérés. Mon entité ressemble à ceci:

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

Le service chargé de renvoyer le contenu est défini comme:

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

Comment renvoyer un JSON «propre» à partir d'un service WCF? Je vous remercie!

user208662
la source
SOAP doit retourner XML. Vous pouvez utiliser un point de terminaison REST pour renvoyer JSON. Jetez un coup d'oeil stackoverflow.com/questions/186631/…
Akira Yamamoto
4
Soit dit en passant, si quelqu'un d'autre rencontre cela et se demande pourquoi la propriété "d" est là, elle est là pour corriger une vulnérabilité JSON . Le supprimer vous rend à nouveau vulnérable.
Alex
4
@Alex - cette vulnérabilité dépend de la redéfinition de l'objet Array, qui n'est plus possible dans les navigateurs modernes. Voir stackoverflow.com/questions/16289894/…
Cheeso
C'est bon. :) La moitié de ma réponse est toujours vraie - elle était là pour corriger cette vulnérabilité.
Alex

Réponses:

213

Modifiez le type de retour de vos GetResults List<Person>.
Éliminez le code que vous utilisez pour sérialiser la liste en une chaîne json - WCF le fait automatiquement pour vous.

En utilisant votre définition de la classe Person, ce code fonctionne pour moi:

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;
}

résultats:

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

(Tout sur une seule ligne)

J'ai également utilisé cet attribut sur la méthode:

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

WebInvoke avec Method = "GET" est le même que WebGet, mais comme certaines de mes méthodes sont POST, j'utilise tous WebInvoke pour la cohérence.

L'UriTemplate définit l'URL à laquelle la méthode est disponible. Je peux donc faire un GET http://myserver/myvdir/JsonService.svc/playerset ça fonctionne.

Consultez également IIRF ou un autre réécriveur d'URL pour vous débarrasser du .svc dans l'URI.

Cheeso
la source
Cheeso - J'ai essayé cette approche avant de poster cette question. Lorsque j'utilise cette approche, j'obtiens une erreur indiquant que "les points de terminaison utilisant 'UriTemplate' ne peuvent pas être utilisés avec 'System.ServiceModel.Description.WebScriptEnablingBehavior'." Qu'est-ce que je fais mal? Je vous remercie!
user208662
28
utilisez <webHttp /> au lieu de <webScriptEnablingBehavior /> dans votre fichier .config.
Cheeso
9
OK, j'ai remplacé <enableWebScript /> par <webHttp /> et cela a fonctionné.
MGOwen
3
MGowen - Pour info, le meilleur pari pour poser une nouvelle question est de ... ouvrir une nouvelle question, plutôt que de poster la question en tant que commentaire d'une ancienne réponse.
Cheeso
5
Favre voit ce que vous y avez fait.
ruffin
93

Si vous voulez un json sympa sans attributs de codage en dur dans vos classes de service,

utiliser <webHttp defaultOutgoingResponseFormat="Json"/>dans votre configuration de comportement

JeremyWeir
la source
8

J'ai rencontré le même problème et l'ai résolu en modifiant la valeur d'attribut BodyStyle en "WebMessageBodyStyle.Bare":

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

L'objet retourné ne sera plus encapsulé.

KhalilG
la source
1

Lorsque vous utilisez la méthode GET, le contrat doit être le suivant.

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

avec cela, nous avons un json sans le paramètre de démarrage

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

alduar
la source
1

Dans votre IServece.cs, ajoutez la balise suivante: BodyStyle = WebMessageBodyStyle.Bare

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

    List<personClass> Getperson(string id);
Osama Ibrahim
la source
pouvez-vous également expliquer pourquoi BodyStyle peut affecter le résultat?
MBH