Od this blog post udało mi się utworzyć niestandardową funkcję WCF IDispatchMessageFormatter
, która korzysta z serializacji JSON.NET. Działa to świetnie z jednym zastrzeżeniem: używanie go z UriTemplate
niekoniecznie działa zgodnie z oczekiwaniami.Używanie niestandardowej deserializacji ciał WCF bez zmiany deserializacji szablonu URI
Oto realizacja zapewnia blogu:
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) { ... }
}
Zasadniczo object[] parameters
w podpisie DeserializeMethod
są out
parametry, że ta metoda musi instancji.
Tak, to robi wielką pracę do obsługi punktu końcowego REST tak:
[WebInvoke(Method="POST", UriTemplate="foo/")]
public Foo MakeFoo(Foo foo) { ... }
lub takiego:
[WebInvoke(Method="POST", UriTemplate="FooBar/")]
public FooBar FooBar(Foo foo, Bar bar) { .. }
ale w tej chwili nie ma map parametrów szablonów do URI parametry metody, np coś takiego:
[WebGet(UriTemplate="Foo/{id}")]
public Foo GetFoo(string id) { ... }
Microsoft pisze na nadpisane GetRequestDispatchFormatter
:
Jest to punkt rozciągliwość że pochodzi zachowania można użyć do zasilania własnego realizację IDispatchMessageFormatter że jest powołany do deserializowania parametrów wejściowych operacja usługi z komunikatu żądania. Parametry określone w UriTemplate operacji usługi muszą zostać przekształcone do postaci szeregowej z identyfikatora To URI komunikatu żądania, a inne parametry muszą zostać przekształcone z postaci szeregowej z treści komunikatu żądania.
Świetne. Zaktualizowałem deserializację parametrów z treści wiadomości. Ale nie chcę przesłonić deserializacji parametrów w UriTemplate
. Czy istnieje sposób użycia istniejącego kodu do odwzorowania przychodzącego żądania URI do parametrów przy użyciu domyślnego sposobu obsługi UriTemplate
?
Wygląda na to, że muszę użyć czegoś takiego, jak UriTemplateDispatchFormatter
, ale nie jestem pewien, jak to zaimplementować, i jest niepubliczne.
bardzo pragmatyczne podejście! Należy pamiętać o tym, że implementacja NewtonsoftJsonDispatchFormatter @ carlosfigueira oczekuje, że pierwsza część ciała będzie bryłą ładunku. Jeśli metoda jest skonstruowana w taki sposób, że część ciała nie jest pierwszym argumentem, prawdopodobnie spowoduje to 'JsonReaderException'. – Tedford
Witam, skończyłem z tym samym problemem, czy nadal jest to najlepsze dostępne rozwiązanie?Próbuję go wypróbować, ale nie jestem fanem kopiowania kodu z frameworka w moim własnym rozwiązaniu, ale no cóż ... – Vinhent
@Jeżeli lepszym rozwiązaniem może być użycie czegoś innego niż WCF dla usługi internetowej RESTful, ale jeśli musisz trzymać się WCF, tak jest –