Использование пользовательской десериализации тела WCF без изменения десериализации шаблона URI
Отэтот блогЯ смог создать собственный WCFIDispatchMessageFormatter
который использует сериализацию JSON.NET. Он прекрасно работает с одной оговоркой: используя его сUriTemplate
не обязательно работает, как ожидалось.
Вот реализация, обеспеченная сообщением в блоге:
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 To сообщения-запроса, а другие параметры должны быть десериализованы из тела сообщения-запроса.
Так здорово. Я обновил десериализацию параметров из тела сообщения. Но я не хочу отменять десериализацию параметров вUriTemplate
, Есть ли способ использовать существующий код для сопоставления входящего запроса URI с параметрами по умолчаниюUriTemplate
обрабатывается?
Кажется, мне нужно использовать что-то вродеUriTemplateDispatchFormatter
но я не уверен, как это реализовать, и это не публично.