Von this blog post konnte ich eine benutzerdefinierte WCF IDispatchMessageFormatter
erstellen, die JSON.NET-Serialisierung verwendet. Es funktioniert gut mit einem Vorbehalt: die Verwendung mit UriTemplate
funktioniert nicht unbedingt wie erwartet.Benutzerdefinierte WCF-Body-Deserialisierung ohne Änderung der URI-Template-Deserialisierung verwenden
Hier ist die Umsetzung durch die Blog-Post zur Verfügung gestellt:
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) { ... }
}
Grundsätzlich ist die object[] parameters
in der DeserializeMethod
Signatur sind out
Parameter, die diese Methode instanziiert muss.
Also, tut dies eine große Aufgabe einen REST-Endpunkt wie folgt zu behandeln:
[WebInvoke(Method="POST", UriTemplate="foo/")]
public Foo MakeFoo(Foo foo) { ... }
oder so:
[WebInvoke(Method="POST", UriTemplate="FooBar/")]
public FooBar FooBar(Foo foo, Bar bar) { .. }
aber derzeit Karte nicht die Vorlage URI-Parameter die Methodenparameter, z so etwas wie dieses:
[WebGet(UriTemplate="Foo/{id}")]
public Foo GetFoo(string id) { ... }
Microsoft schreibt auf die GetRequestDispatchFormatter
außer Kraft gesetzt:
Dies ist ein Erweiterungspunkt, die Verhaltensweisen abgeleitet verwenden können, ihre eigene Implementierung von IDispatchMessageFormatter zu liefern, die die Eingangsparameter deserialisieren genannt wird die Dienstoperation von der Anforderungsnachricht. Parameter, die in der UriTemplate der Dienstoperation angegeben sind, müssen aus dem To-URI der Anforderungsnachricht deserialisiert werden, und andere Parameter müssen aus dem Hauptteil der Anforderungsnachricht deserialisiert werden.
Also, großartig. Ich habe die Deserialisierung der Parameter aus dem Nachrichtentext aktualisiert. Aber ich möchte die Deserialisierung der Parameter in UriTemplate
nicht außer Kraft setzen. Gibt es eine Möglichkeit, vorhandenen Code zu verwenden, um die eingehende URI-Anforderung den Parametern mit der Standardmethode UriTemplate
zuzuordnen?
Es scheint, dass ich etwas wie die UriTemplateDispatchFormatter
verwenden muss, aber ich bin nicht sicher, wie man das umsetzt, und es ist nicht öffentlich.
sehr pragmatischen Ansatz! Beachten Sie, dass die Implementierung von NewtonsoftJsonDispatchFormatter von @ carlosfigeira erwartet, dass der erste Körperteil der Nutzlastkörper ist. Wenn die Methode so strukturiert ist, dass der Körperteil nicht das erste Argument ist, wird dies wahrscheinlich zu einer "JsonReaderException" führen. – Tedford
Hallo, ich hatte das gleiche Problem, ist es immer noch die beste verfügbare Lösung?Ich versuche es, aber ich bin nicht Fan von Code kopieren aus dem Framework in meiner eigenen Lösung, aber na ja ... – Vinhent
@Vinhent die bessere Lösung könnte etwas anderes als WCF für einen RESTful Web-Service verwenden, aber wenn Sie müssen bei WCF bleiben ja ist es –