Как прочитать тело объекта Message при реализации IDispatchMessageFormatter для пользовательской (де) сериализации службы REST WCF? - PullRequest
2 голосов
/ 10 мая 2011

Я расширяю WebHttpBehavior для предоставления службы WCF REST с настраиваемой сериализацией и десериализацией (плюс определенное количество других функций, не имеющих отношения к проблеме).

В новом поведении используется реализация IDispatchMessageFormatter для выполнения настраиваемой сериализации и десериализации POCO, обслуживаемых службой и отправляемых ей благодаря SerializeReply и DeserializeRequest методы.

Я могу обслуживать XML и JSON именно так, как они мне нужны в SerializeReply.

Я могу десериализовать XML без проблем, однако я не могу найти способ десериализации сообщения JSON, потому что не могу получить простой текст, содержащийся в параметре Message в DeserializeRequest.

Вот как выглядит код в DeserializeRequest прямо сейчас:

if (format == System.ServiceModel.Web.WebMessageFormat.Json)
{
    var data = ""; // TODO obtain plain text from Message object

    var json = JsonConvert.DeserializeObject(data, paramType, new IsoDateTimeConverter(), new StringEnumConverter());

    parameters[paramIndex] = json;
}
else
{
    var serializer = new System.Xml.Serialization.XmlSerializer(paramType, string.Empty);

    var reader = message.GetReaderAtBodyContents();

    parameters[paramIndex] = serializer.Deserialize(reader);
}

Я использую Json.NET для сериализации JSON (de).

Будем весьма благодарны за любые предложения о том, как получить простой текст из объекта Message для его десериализации.

Если вы считаете, что в моем подходе что-то не так, я также хотел бы услышать об этом в комментариях.

Ответы [ 2 ]

13 голосов
/ 10 мая 2011

Необходимо убедиться, что WebMessageFormat сообщения установлено на Raw , в противном случае WCF будет использовать JsonMessageEncoder для создания Message, что, в свою очередь, не будет позволяют вам перейти к необработанному содержанию сообщения.

Вы делаете это путем реализации пользовательского WebContentTypeMapper:

public class RawMapper : WebContentTypeMapper
{
    public override WebContentFormat GetMessageFormatForContentType(string contentType)
    {
        return WebContentFormat.Raw;
    }
}

... который необходимо применить к привязке WebHttp:

webHttpBinding.ContentTypeMapper = new RawMapper();

.. или через конфигурацию:

<bindings>
  <webHttpBinding>
    <binding contentTypeMapper="Samples.RawMapper, MyContentTypeMapperAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  </webHttpBinding>
</bindings>

После этого вы можете получить тело запроса в виде строки:

    public void DeserializeRequest(Message message, object[] parameters)
    {
        var bodyReader = message.GetReaderAtBodyContents();
        bodyReader.ReadStartElement("Binary");
        byte[] rawBody = bodyReader.ReadContentAsBase64();

        string messageAsString;
        using (var reader = new StreamReader(new MemoryStream(rawBody)))
            messageAsString = reader.ReadToEnd();

        object jsonObj = JsonConvert.DeserializeObject(messageAsString);

        parameters[0] = jsonObj;
    }
3 голосов
/ 15 августа 2014

Даже если вы используете WebMessageFormat.Json, вы можете преобразовать ваше сообщение в строку и затем десериализовать его в объект внутри метода DeserializeRequest.

MemoryStream mss = new MemoryStream();
XmlDictionaryWriter writer = JsonReaderWriterFactory.CreateJsonWriter(mss);
message.WriteMessage(writer);
writer.Flush();
string messageBody = Encoding.UTF8.GetString(mss.ToArray());

var obj = JsonConvert.DeserializeObject(messageBody, operation.Messages[0].Body.Parts[0].Type);

parameters[0] = obj;
...