從this blog post開始,我能夠創建使用JSON.NET序列化的自定義WCF IDispatchMessageFormatter
。它與一個警告很好地工作:與UriTemplate
使用它不一定按預期工作。在不更改URI模板反序列化的情況下使用自定義WCF正文反序列化
這裏是由博客帖子提供的實現:
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) { ... }
}
基本上,DeserializeMethod
簽名object[] parameters
是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) { ... }
微軟寫在重寫GetRequestDispatchFormatter
:
這是派生的行爲可以用它來提供自己的實現IDispatchMessageFormatter的被稱爲反序列化的輸入參數的可擴展性點來自請求消息的服務操作。在服務操作的UriTemplate中指定的參數必須從請求消息的To URI反序列化,並且其他參數必須從請求消息的正文中反序列化。
所以,太棒了。我更新了消息正文中參數的反序列化。但我不想重寫反序列化UriTemplate
中的參數。有什麼方法可以使用現有的代碼將傳入的URI請求映射到參數中,默認方式是UriTemplate
被處理?
看來我需要使用類似UriTemplateDispatchFormatter
的東西,但我不知道如何實現這一點,它是非公開的。
非常務實的做法!有一點需要記住的是@ carlosfigueira的NewtonsoftJsonDispatchFormatter實現需要第一個正文部分是有效負載體。如果方法的結構使得body部分不是第一個參數,它可能會導致'JsonReaderException'。 – Tedford
嗨,我結束了同樣的問題,它仍然是最好的解決方案嗎?我試了一下,但我並不喜歡在我自己的解決方案中從框架中複製代碼,但噢... – Vinhent
@Vinhent更好的解決方案可能是使用WCF以外的其他方法來實現RESTful Web服務,但如果你需要堅持WCF是的 –