Как я могу возвратить json из своей службы отдыха WCF (.NET 4), с помощью Json. Сеть, без него являющийся строкой, перенесенной в кавычки?

ОБНОВИТЕ 19.10.2010, я знаю, что задал этот вопрос только что, но обходные решения, показанные в этих ответах, являются едва удовлетворительными, и это - все еще типичная проблема для многих. WCF просто не гибок. Я запустил свою собственную библиотеку C# с открытым исходным кодом для создания сервисов REST без WCF. Проверьте restcake.net или rest.codeplex.com для получения информации об упомянутой библиотеке. ОБНОВЛЕНИЕ КОНЦА

ОБНОВИТЕ 02.08.2012 сеть ASP.NET, API (ранее сеть WCF API, замена для REST WCF) использует Json.NET ОБНОВЛЕНИЕМ КОНЦА по умолчанию

DataContractJsonSerializer не может обработать много сценариев что Json. Сеть обрабатывает очень хорошо, когда правильно настроено (а именно, циклы).

Сервисный метод может или возвратить тип конкретного объекта (в этом случае DTO), в этом случае DataContractJsonSerializer будет использоваться, или я могу иметь возврат метода строка и сделать сериализацию сам с Json. Сеть. Проблема состоит в том, что, когда я возвращаю строку json в противоположность объекту, json, который отправляется клиенту, перенесен в кавычки.

Используя DataContractJsonSerializer, возвращая тип конкретного объекта, ответ:
{"Message":"Hello World"}

Использование Json. Сеть для возврата строки json ответ:
"{\"Message\":\"Hello World\"}"

Я не хочу иметь к оценке () или JSON.parse () результат на клиенте, который является тем, что я должен был бы сделать, если json возвращается как строка, перенесенная в кавычки. Я понимаю, что поведение корректно; это просто не, что я хочу/нуждаюсь. Мне нужны сырые данные json; поведение, когда сервисный тип возврата метода является объектом, не строкой.

Так, как я могу иметь свой возврат метода тип объекта, но не использовать DataContractJsonSerializer? Как я могу сказать этому использовать Json. Сетевой сериализатор вместо этого?

Или, должен там некоторым образом непосредственно записать в ответный поток? Таким образом, я могу просто возвратить сырые данные json сам? Без переносящихся кавычек?

Вот мой изобретенный пример для ссылки:

[DataContract]
public class SimpleMessage
{
    [DataMember]
    public string Message { get; set; }
}

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PersonService
{
    // uses DataContractJsonSerializer
    // returns {"Message":"Hello World"}
    [WebGet(UriTemplate = "helloObject")]
    public SimpleMessage SayHelloObject()
    {
        return new SimpleMessage("Hello World");
    }

    // uses Json.Net serialization, to return a json string
    // returns "{\"Message\":\"Hello World\"}"
    [WebGet(UriTemplate = "helloString")]
    public string SayHelloString()
    {
        SimpleMessage message = new SimpleMessage() { Message = "Hello World" };
        string json = JsonConvert.Serialize(message);
        return json;
    }

    // I need a mix of the two.  Return an object type, but use the Json.Net serializer.
}

40
задан James Newton-King 1 August 2012 в 23:48
поделиться

2 ответа

Я наконец нашел решение этой проблемы. Это не то, что я предпочел бы (возвращать конкретный тип объекта и каким-то образом указывать WCF использовать сериализатор Json.Net вместо DataContractJsonSerializer), но он отлично работает, прост и понятен.

Расширение моего надуманного примера с помощью этого нового решения:

[WebGet(UriTemplate = "hello")]
public void SayHello()
{
    SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
    string json = JsonConvert.Serialize(message);
    HttpContext.Current.Response.ContentType = "application/json; charset=utf-8";
    HttpContext.Current.Response.Write(json);
}

Обратите внимание на возвращаемый тип void . Мы ничего не возвращаем, так как это будет сериализовано с помощью DataContractJsonSerializer. Вместо этого я пишу прямо в выходной поток ответа. Поскольку тип возвращаемого значения недействителен, конвейер обработки не устанавливает для типа содержимого значение по умолчанию «application / json», поэтому я установил его явно.

Поскольку здесь используется HttpContext , я предполагаю, что он будет работать только в том случае, если у вас есть [AspNetCompatibilityRequirements (RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] в вашем классе обслуживания, поскольку это заставит запросы к службе для прохождения конвейера ASP.NET. Без совместимости с asp.net HttpContext будет недоступен, поскольку предполагается, что хостинг wcf не зависит от хоста.

Используя этот метод, результаты выглядят идеально в firebug для запросов GET. Правильный тип содержимого, правильная длина содержимого и необработанный json, не заключенный в кавычки. И я получаю сериализацию, которую хочу, используя Json.Net. Лучшее из обоих миров.

Я не уверен на 100% в том, с какими препятствиями я могу столкнуться при сериализации de , когда мои методы службы имеют типы объектов [DataContract] в качестве входных параметров. Я предполагаю, что для этого также будет использоваться DataContractJsonSerializer. Перейду через этот мост, когда подойду к нему ... если это создаст проблемы. С моими простыми DTO этого не произошло.

ОБНОВЛЕНИЕ См. Ответ Олега (часть UPDATE2). Он изменяет тип возвращаемого значения метода службы с void на System.ServiceModel.Channels.Message , и вместо использования HttpContext.Current.Response.Write () он использует:

return WebOperationContext.Current.CreateTextResponse (json,
    "application/json; charset=utf-8", Encoding.UTF8);

Что действительно является лучшим решением. Спасибо Олег.

ОБНОВЛЕНИЕ 2 Есть еще один способ добиться этого. Измените тип возвращаемого значения вашей службы с Message на Stream и верните следующее:

WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));

Я не проводил никаких конкретных тестов, но возможно, что это будет лучший выбор для методов, которые потенциально могут возвращать большие объемы данных. Я не знаю, имеет ли это значение для недвоичных данных. Во всяком случае, мысль.

40
ответ дан 27 November 2019 в 01:50
поделиться

Мне кажется, что вы используете неверный DataContractJsonSerializer . Что странно: вы не определяете атрибут ResponseFormat = ResponseFormat.Json для общедоступного метода SimpleMessage SayHelloObject () .

Более того, если у вас есть {"Message": "Hello World"} в строке и вы отображаете ее в отладчике, она будет отображаться как "{\" Message \ ": \" Hello Мир \ "}" , так что в точности как вы видите string json = JsonConvert.Serialize (message); (Json.Net). Мне кажется, что в обоих случаях результаты одинаковые.

Чтобы проверить это, используйте клиентское программное обеспечение, которое считывает результаты. См. Некоторые примеры

JQuery ajax-вызов httpget webmethod (c #) не работает

Могу ли я вернуть JSON из веб-службы .asmx, если ContentType не является JSON?

Как создать объект JSON для отправки на AJAX WebService?

ОБНОВЛЕНО : В вашем коде вы определяете метод SayHelloString () . Результат - строка. Если вы вызовете метод, эта строка будет еще раз сериализованным JSON. JSON-сериализация строки {"Message": "Hello World"} - строка в кавычках (см. http://www.json.org/ определение не объекта, но строка) или точно строка "{\" Сообщение \ ": \" Hello World \ "}" . Итак, все верно с обоими методами вашего веб-сервиса.

ОБНОВЛЕНИЕ 2 : я рад, что мой совет из части моего ответа «Обновление» помог вам переключить двойную сериализацию JSON.

Тем не менее, я бы порекомендовал вам немного изменить решение, чтобы больше придерживаться концепции WCF.

Если вы хотите реализовать настраиваемую кодировку веб-ответа в WCF (см. http://msdn.microsoft.com/en-us/library/ms734675.aspx ), ваш метод WCF должен лучше возвращать Сообщение вместо void :

[WebGet(UriTemplate = "hello")]
public Message SayHello()
{
    SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
    string myResponseBody = JsonConvert.Serialize(message);
    return WebOperationContext.Current.CreateTextResponse (myResponseBody,
                "application/json; charset=utf-8",
                Encoding.UTF8);
}

Вы, конечно, можете использовать другое средство форматирования сообщений: например, CreateStreamResponse (или другое см. http: // msdn.microsoft.com/en-us/library/system.servicemodel.web.weboperationcontext_methods(v=VS.100).aspx) вместо CreateTextResponse . Если вы хотите установить дополнительные HTTP-заголовки или код статуса Http (например, в случае какой-либо ошибки), вы можете сделать это следующим образом:

OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
ctx.StatusCode = HttpStatusCode.BadRequest;

В конце я хочу повторить свой вопрос из комментария: не могли бы вы объяснить, почему вы хотите использовать Json.Net вместо DataContractJsonSerializer ? Это улучшение производительности? Вам нужно реализовать сериализацию некоторых типов данных, таких как DateTime , другим способом, как это делают DataContractJsonSerializer ? Или основная причина вашего выбора Json.Net - какая-то другая?

11
ответ дан 27 November 2019 в 01:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: