От this blog post мне удалось создать пользовательский WCF IDispatchMessageFormatter
, который использует сериализацию JSON.NET. Он отлично работает с одним предостережением: использование его с UriTemplate
не обязательно работает должным образом.Использование пользовательской десерциализации тела WCF без изменения десериализации шаблона URI
Вот реализация обеспечивается запись в блоге:
class NewtonsoftJsonDispatchFormatter : IDispatchMessageFormatter
{
private readonly OperationDescription od;
private readonly ServiceEndpoint ep;
private readonly Dictionary<string, int> parameterNames = new Dictionary<string, int>();
public NewtonsoftJsonDispatchFormatter(OperationDescription od, ServiceEndpoint ep, bool isRequest)
{
this.od = od;
this.ep = ep;
if (isRequest)
{
int operationParameterCount = od.Messages[0].Body.Parts.Count;
if (operationParameterCount > 1)
{
this.parameterNames = new Dictionary<string, int>();
for (int i = 0; i < operationParameterCount; i++)
{
this.parameterNames.Add(od.Messages[0].Body.Parts[i].Name, i);
}
}
}
}
public void DeserializeRequest(Message message, object[] parameters)
{
if (message.IsEmpty)
return;
object bodyFormatProperty;
if (!message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out bodyFormatProperty) ||
(bodyFormatProperty as WebBodyFormatMessageProperty).Format != WebContentFormat.Raw)
{
throw new InvalidOperationException("Incoming messages must have a body format of Raw. Is a ContentTypeMapper set on the WebHttpBinding?");
}
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
bodyReader.ReadStartElement("Binary");
byte[] rawBody = bodyReader.ReadContentAsBase64();
using (MemoryStream ms = new MemoryStream(rawBody))
using (StreamReader sr = new StreamReader(ms))
{
if (parameters.Length == 1)
parameters[0] = Helper.serializer.Deserialize(sr, od.Messages[0].Body.Parts[0].Type);
else
{
// multiple parameter, needs to be wrapped
using (Newtonsoft.Json.JsonReader reader = new Newtonsoft.Json.JsonTextReader(sr))
{
reader.Read();
if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
throw new InvalidOperationException("Input needs to be wrapped in an object");
reader.Read();
while (reader.TokenType == Newtonsoft.Json.JsonToken.PropertyName)
{
string parameterName = reader.Value as string;
reader.Read();
if (this.parameterNames.ContainsKey(parameterName))
{
int parameterIndex = this.parameterNames[parameterName];
parameters[parameterIndex] = Helper.serializer.Deserialize(reader, this.od.Messages[0].Body.Parts[parameterIndex].Type);
}
else
reader.Skip();
reader.Read();
}
}
}
}
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) { ... }
}
В принципе, object[] parameters
в DeserializeMethod
подписей являются out
параметрами, что этот метод необходим для создания экземпляра.
Таким образом, это делает большую работу, чтобы справиться с REST конечной точки, как это:
[WebInvoke(Method="POST", UriTemplate="foo/")]
public Foo MakeFoo(Foo foo) { ... }
или вроде этого:
[WebInvoke(Method="POST", UriTemplate="FooBar/")]
public FooBar FooBar(Foo foo, Bar bar) { .. }
, но в настоящее время он не отображает параметры URI шаблонный параметры метода, например что-то вроде этого:
[WebGet(UriTemplate="Foo/{id}")]
public Foo GetFoo(string id) { ... }
Microsoft пишет на перекрываться GetRequestDispatchFormatter
:
Это точка расширяемости, что полученные модели поведения можно использовать для обеспечения их собственной реализации IDispatchMessageFormatter, что называется десериализовать входные параметры операция обслуживания из сообщения запроса. Параметры, указанные в UriTemplate операции службы, должны быть десериализованы из URI сообщения запроса, а другие параметры должны быть десериализованы из тела сообщения запроса.
Итак, отлично. Я обновил десериализацию параметров из тела сообщения. Но я не хочу отменять десериализацию параметров в UriTemplate
. Есть ли способ использовать существующий код для сопоставления входящего запроса URI с параметрами по умолчанию, с которым обрабатывается UriTemplate
?
Кажется, мне нужно использовать что-то вроде UriTemplateDispatchFormatter
, но я не уверен, как реализовать это, и он не является общедоступным.
очень прагматичный подход! Одна вещь, о которой следует помнить, заключается в том, что реализация NewtonsoftJsonDispatchFormatter @ carlosfigueira предполагает, что первая часть тела будет частью полезной нагрузки. Если метод структурирован так, что часть тела не является первым аргументом, это, скорее всего, приведет к 'JsonReaderException'. – Tedford
Привет, у меня в результате была такая же проблема, это все-таки лучшее решение?Я даю ему попробовать, но я не поклонник копирования кода из фреймворка в моем собственном решении, но хорошо ... – Vinhent
@Vinhent лучшим решением может быть использование чего-то другого, кроме WCF для веб-службы RESTful, но если вам нужно придерживаться WCF, да, это –