Como retorno JSON limpo de um serviço WCF?

233

Estou tentando retornar algum JSON de um serviço WCF. Este serviço simplesmente retorna algum conteúdo do meu banco de dados. Eu posso pegar os dados. No entanto, estou preocupado com o formato do meu JSON. Atualmente, o JSON retornado está formatado da seguinte maneira:

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

Na realidade, eu gostaria que meu JSON fosse formatado da maneira mais limpa possível. Acredito (posso estar incorreto), que a mesma coleção de resultados, representada em JSON limpo, tenha a seguinte aparência:

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

Não tenho ideia de onde o "d" vem. Também não tenho idéia por que os caracteres de escape estão sendo inseridos. Minha entidade se parece com o seguinte:

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

O serviço responsável pela devolução do conteúdo é definido como:

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

Como retorno JSON "limpo" de um serviço WCF? Obrigado!

user208662
fonte
SOAP deve retornar XML. Você pode usar um terminal REST para retornar JSON. Dê uma olhada stackoverflow.com/questions/186631/…
Akira Yamamoto
4
A propósito, se alguém mais se deparar com isso e se perguntar por que a propriedade "d" está lá, está lá para corrigir uma vulnerabilidade JSON . Removê-lo torna você vulnerável novamente.
214 Alex
4
@Alex - essa vulnerabilidade depende da redefinição do objeto Array, que não é mais possível nos navegadores modernos. Veja stackoverflow.com/questions/16289894/…
Cheeso
Isso é bom. :) Metade da minha resposta ainda é verdadeira - estava lá para corrigir essa vulnerabilidade.
22415 Alex

Respostas:

213

Altere o tipo de retorno dos seus GetResults para ser List<Person>.
Elimine o código que você usa para serializar a Lista em uma string json - o WCF faz isso automaticamente.

Usando sua definição para a classe Person, esse código funciona para mim:

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

resultados:

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

(Tudo em uma linha)

Eu também usei esse atributo no método:

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

WebInvoke com Method = "GET" é o mesmo que WebGet, mas como alguns dos meus métodos são POST, eu uso todo o WebInvoke por consistência.

O UriTemplate define o URL no qual o método está disponível. Então eu posso fazer um GET http://myserver/myvdir/JsonService.svc/playerse ele simplesmente funciona.

Verifique também o IIRF ou outro reescritor de URL para se livrar do .svc no URI.

Cheeso
fonte
Cheeso - Eu tentei essa abordagem antes de postar esta pergunta. Quando uso essa abordagem, recebo um erro que diz que "Pontos de extremidade usando 'UriTemplate' não podem ser usados ​​com 'System.ServiceModel.Description.WebScriptEnablingBehavior'." O que estou fazendo de errado? Obrigado!
precisa saber é o seguinte
28
use <webHttp /> em vez de <webScriptEnabledBehavior /> no seu arquivo .config.
Cheeso
9
OK, substituí <enableWebScript /> por <webHttp /> e funcionou.
MGOwen
3
MGowen - FYI, a melhor aposta ao fazer uma nova pergunta é ... abrir uma nova pergunta, em vez de postar a pergunta como um comentário em uma resposta antiga.
Cheeso
5
Favre vê o que você fez lá.
ruffin
93

Se você deseja um bom json sem atributos codificados nas suas classes de serviço,

use <webHttp defaultOutgoingResponseFormat="Json"/>na sua configuração de comportamento

JeremyWeir
fonte
8

Eu enfrentei o mesmo problema e resolvi-o alterando o valor do atributo BodyStyle para "WebMessageBodyStyle.Bare":

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

O objeto retornado não será mais quebrado.

KhalilG
fonte
1

Quando você está usando o método GET, o contrato deve ser este.

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

com isso, temos um json sem o parâmetro de inicialização

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

alduar
fonte
1

No seu IServece.cs, adicione a seguinte tag: BodyStyle = WebMessageBodyStyle.Bare

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

    List<personClass> Getperson(string id);
Osama Ibrahim
fonte
você também pode explicar por que o BodyStyle pode afetar o resultado?
MBH