我需要支持将数据发布到我们的WCF服务中,其内容类型为x-www-form-urlencoded
。由于WCF不喜欢在本地执行此操作,因此我想到的是使用MessageInspector
来拦截具有该内容类型的传入消息,读出正文,将其转换为JSON字符串,然后替换请求消息
问题是我似乎无法创建一个我的服务实际上喜欢的新Message
对象。我可以获取它的主体并将其转换为JSON字符串,但是我创建的新消息会导致错误,而不是继续执行相应的服务方法。
这是我目前所拥有的。我已经整整一天的时间,尝试了几种不同的方式,但是运气不佳。我将在当前出现的错误下方发布。
我要调用的Web服务方法:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/PostTest", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public string PostTest(TestObject thinger)
{
return thinger.Thing;
}
消息检查器:
public class FormPostConverter : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
var contentType = (request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty)?.Headers["Content-Type"];
if (!request.IsEmpty && contentType == "application/x-www-form-urlencoded")
{
var body = HttpUtility.ParseQueryString(new StreamReader(request.GetBody<Stream>()).ReadToEnd());
var json = new JavaScriptSerializer().Serialize(body.AllKeys.ToDictionary(k => k, k => body[k]));
Message newMessage = Message.CreateMessage(MessageVersion.None, "", json, new DataContractJsonSerializer(typeof(string)));
newMessage.Headers.CopyHeadersFrom(request);
newMessage.Properties.CopyProperties(request.Properties);
(newMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty)?.Headers.Set(HttpRequestHeader.ContentType, "application/json");
newMessage.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
request = newMessage;
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{ }
}
我得到的错误:
请求错误服务器在处理请求时遇到错误。 异常消息为“预期状态为'元素'。。 名称为“,名称空间为”的“文本”。 '。
答案 0 :(得分:0)
所以,看来我实际上并没有很好地说明我实际上要完成的工作,但是在与之抗争之后,我终于弄清楚了。
我得到的MessageInspector看起来像这样:
public class FormPostConverter : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
var contentType = (request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty)?.Headers["Content-Type"];
if (!request.IsEmpty && contentType == "application/x-www-form-urlencoded")
{
var body = HttpUtility.ParseQueryString(new StreamReader(request.GetBody<Stream>()).ReadToEnd());
if (body != null && body.HasKeys())
{
Message newMessage = Message.CreateMessage(MessageVersion.None, "", new XElement("root", body.AllKeys.Select(o => new XElement(o, body[o]))));
newMessage.Headers.CopyHeadersFrom(request);
newMessage.Properties.CopyProperties(request.Properties);
(newMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty)?.Headers.Set(HttpRequestHeader.ContentType, "application/json");
newMessage.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
request = newMessage;
}
}
return true;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{ }
}
结果,我真正需要做的就是将我的身体变成XML元素,而不是尝试将其作为JSON。在检查了以JSON开头的正常运行的POST之后,我发现在这个阶段它已经在Message对象中变成了XML。
有了这个,我就能正常编写我的服务方法(没有Stream参数并手动解析),并接受application / json或x-www-form-urlencoded内容类型中的帖子。