WCF service web RESTful avec JSON.Net: éviter le double de la sérialisation

Longtemps à l'envers, affiche la première fois ici.
J'ai été aux prises avec ce problème depuis quelques jours maintenant et vous serions reconnaissants de tout conseils.
Je suis en panne ici, le problème ci-dessous.

Ce que je suis en train de réaliser:

Je veux mettre en place un JSON service web WCF, mais je veux utiliser le JSON.net sérialiseur à la place de celui qui vient avec WCF. Pourquoi? Parce que j'ai trouvé que la sérialisation à l'aide de celui qui vient avec WCF gonfle de collections (je vais vous montrer un exemple de ce que je veux dire ci-dessous). Le consommateur du service va être un client de JavaScript, donc je ne veut pas que le client n'supplémentaire de déconner à naviguer à travers le JSON.

Je suis venu avec un exemple simple de ce que je voulais et se mirent à essayer de le faire fonctionner en C#. J'avoue ne pas avoir utilisé .NET dans un temps long, ce qui contribue peut-être à ma lenteur. De toute façon, j'ai la patience en stock sur.

Donc, je veux un service qui accepte un nom d'utilisateur et renvoie un objet JSON avec quelques infos sur l'utilisateur.
J'ai envisagé le service s'appeler quelque chose comme ceci:

http://someHostName/whoareyou?username=paul

Et avoir le service de répondre à ceci:

{
    "errorCode": 0,
    "payLoad"  :  {
        "userFullName": "Paul The Octopus",
        "userLevel"        : "Administrator"
    }
}

Je pouvais utiliser le ci-dessus la réponse de l'objet JSON JavaScript ou PHP facilement et se sentir vraiment bien sur moi-même.

Après quelques recherches sur google, je suis tombé sur certains postes, ce qui suggère que cela serait facile à faire avec WCF .NET Framework 4. J'avais fait de jongler avec la WCF à un cours il y a longtemps, mais avait depuis longtemps oublié 99% de celui-ci alors j'ai trouvé et suivi ce post pour s'adapter à mon objectif:
http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide#

Tentative de prendre 1:

Suivant le post ci-dessus, j'ai été capable de mettre en place un Service WCF (code ci-dessous) qui fait ce que je voulais mais la sortie JSON était un peu gonflé, comme vous pouvez le voir ci-dessous.

RestServiceImpl.svc.cs fichier

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newtonsoft.Json;
using System.Collections.Specialized;
//Based on this psot: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        #region IRestService Members

        public WhoAreYouResponse whoareyou(string username)
        {
            var payLoad = new Dictionary<string, string>
            {
                {"userFullName", "Paul The Octopus"},
                {"userLevel", "Administrator"}
            };

            WhoAreYouResponse whoAreYouResponse = new WhoAreYouResponse
            {
                errorCode = 0,
                payLoad   = payLoad
            };

            return whoAreYouResponse;
        }

        #endregion
    }

    //Helper bits to be used in service implementation
    public class WhoAreYouResponse
    {
        public int errorCode { get; set; }
        public Dictionary<string,string> payLoad { get; set; }
    }
}

IRestServiceImpl.cs fichier

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestService
{
    [ServiceContract]
    public interface IRestServiceImpl
    {
        [OperationContract]
        [WebInvoke(Method = "GET", 
            ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Bare, 
            UriTemplate = "json/whoareyou?username={username}")]
        WhoAreYouResponse whoareyou(string username);
    }
}

Web.fichier de configuration

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="RestService.RestServiceImpl" behaviorConfiguration="ServiceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="RestService.IRestServiceImpl" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

*Résultat de l'appel au service via un navigateur comme ceci http://192.168.0.84/TestRestService/RestServiceImpl.svc/json/whoareyou?username=paul*

{
    "errorCode":0,
    "payLoad"   : [
        {"Key":"userFullName", "Value":"Paul The Octopus"},
        {"Key":"userLevel","Value":"Administrator"}
    ]
}

Le cheveux dans la soupe, la réponse JSON est la façon dont le Dictionnaire de l'objet a été cartographiée dans la réponse JSON pour "charge utile". C'est un tableau d'objets, alors que je m'attendais à un objet JSON sans cette "Clé", "Valeur". Pas tout à fait ce que je voulais. À proximité, mais assez difficiles à gérer au niveau du client final. Personne n'aime la météorisation et le travail inutile, donc, les pouces vers le bas.

En faisant encore plus de pêche à la traîne autour des solutions, j'ai lu quelques posts suggérant ce qui se passe ici est que le service est intégré dans le sérialiseur
et ce n'est pas sérialiser "dictionnaires de toute autre manière". Un travail supplémentaire serait nécessaire pour l'obtenir dans le format que je m'attendais.
Alors, j'ai pensé, pourquoi ne pas utiliser un autre sérialiseur?
Suivant cette pensée, je l'ai découvert sur ce mauvais garçon ici: http://james.newtonking.com/projects/json-net.aspx

Cela a conduit à ma deuxième tentative ci-dessous.

Tentative de prendre 2:

Le téléchargement et l'importation de la JSON.NET sérialiseur dans mon petit projet, j'ai modifié les fichiers suivants à ressembler à ceci (en changeant le type de retour de la whoareyou méthode pour chaîne):

RestServiceImpl.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newtonsoft.Json;
using System.Collections.Specialized;
//Based on this psot: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        #region IRestService Members

        public string whoareyou(string username)
        {
            var payLoad = new Dictionary<string, string>
            {
                {"userFullName", "Paul The Octopus"},
                {"userLevel", "Administrator"}
            };

            WhoAreYouResponse whoAreYouResponse = new WhoAreYouResponse
            {
                errorCode = 0,
                payLoad   = payLoad
            };

            return JsonConvert.SerializeObject(whoAreYouResponse);
        }

        #endregion
    }

    //Helper bits to be used in service implementation
    public class WhoAreYouResponse
    {
        public int errorCode { get; set; }
        public Dictionary<string,string> payLoad { get; set; }
    }
}

IRestServiceImpl.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestService
{
    [ServiceContract]
    public interface IRestServiceImpl
    {
        [OperationContract]
        [WebInvoke(Method = "GET", 
            ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Bare, 
            UriTemplate = "json/whoareyou?username={username}")]
        string whoareyou(string username);
    }
}

Et lorsque le service est appelé, je reçois cette réponse:

"{
\"errorCode\":0,
\"payLoad\":{
    \"userFullName\":\"Paul The Octopus\",
    \"userLevel\":\"Administrator\"}
}"

Gagnant! C'est ce que j'ai voulu et attendu....MAIS. L'arrière du camion. L'ensemble de l'objet JSON est entre guillemets!?
Hmmm. C'est une chaîne de caractères contenant un objet JSON. J'ai pris les cheveux dans la soupe et maintenant une mouche volé!

Après un moment de casse-tête qu'il est devenu évident (je pense) que ce qui se passe est que le JSON.NET sérialiseur se porte comme un charme, en crachant un objet JSON dans une chaîne de caractères, mais qui est alors mis par la WCF sérialiseur et est essentiellement stringified. Donc, ce que je vois sur le retour est une chaîne JSON. Donc de très près! En fait, ma méthode whoareyou dit qu'elle renvoie une chaîne de caractères, donc à peu près de ma faute.

Donc, ma question est, comment puis-je obtenir de ce problème à l'enfant d'arrêter cette double-sérialisation d'affaires? Je ne peux pas trouver le type de retour pour mon whoareyou méthode pour être quelque chose comme objet JSON.
Est-il un moyen de dire à l'utilisation de la WCF JSON.NET sérialiseur au lieu de cela, ou quelque chose comme solution?

Pointeurs beaucoup apprécié.

OriginalL'auteur coderigo | 2012-07-20