我试图从我的ASP.NET 2.0 WebForms应用程序中运行的WCF Web服务获取JQGrid的数据.问题是WCF Web服务期望将数据格式化为JSON字符串,并且JQGrid正在执行HTTP Post并将其作为Content-Type传递:application/x-www-form-urlencoded.
虽然返回到JQGrid的数据格式似乎有几种选择(它接受JSON,XML等),但似乎没有办法改变它将输入传递给Web服务的方式.
所以我试图找出如何调整WCF服务以便它接受
Content-Type: application/x-www-form-urlencoded
而不是
Content-Type:"application/json; charset=utf-8"
当我使用JQuery进行测试以使用url编码发送Ajax请求时(如下所示):
$.ajax({ type: "POST", url: "../Services/DocLookups.svc/DoWork", data: 'FirstName=Howard&LastName=Pinsley', contentType: "Content-Type: application/x-www-form-urlencoded", dataType: "json", success: function(msg) { alert(msg.d); } });
呼叫失败.使用Fiddler检查流量,我发现服务器返回的错误:
{"ExceptionDetail":{"HelpLink":null,"InnerException":null,"Message": "The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml', 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details."...
请注意,由于编码的不同,此代码可以正常工作
$.ajax({ type: "POST", url: "../Services/DocLookups.svc/DoWork", data: '{"FirstName":"Howard", "LastName":"Pinsley"}', contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) { alert(msg.d); } });
在服务器上,该服务看起来像:
[ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class DocLookups { // Add [WebGet] attribute to use HTTP GET [OperationContract] public string DoWork(string FirstName, string LastName) { return "Your name is " + LastName + ", " + FirstName; } }
我的web.config包含:
谢谢你的帮助!
如果你无法控制你的ajax调用,我建议创建和拦截来覆盖内容类型标题.
public class ContentTypeOverrideInterceptor : RequestInterceptor { public string ContentTypeOverride { get; set; } public ContentTypeOverrideInterceptor(string contentTypeOverride) : base(true) { this.ContentTypeOverride = contentTypeOverride; } public override void ProcessRequest(ref RequestContext requestContext) { if (requestContext == null || requestContext.RequestMessage == null) { return; } Message message = requestContext.RequestMessage; HttpRequestMessageProperty reqProp = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name]; reqProp.Headers["Content-Type"] = ContentTypeOverride; } }
然后,如果您查看.svc文件,您将看到并且AppServiceHostFactory类将其更改为包含拦截器
class AppServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { var host = new WebServiceHost2(serviceType, true, baseAddresses); host.Interceptors.Add(new ContentTypeOverrideInterceptor("application/json; charset=utf-8")); return host; } }
那应该为你做.
如评论中所述,上述方法适用于WCF REST入门工具包.如果您只使用常规WCF服务,则必须创建IOperationBehavior并将其附加到您的服务.这是behavior属性的代码
public class WebContentTypeAttribute : Attribute, IOperationBehavior, IDispatchMessageFormatter { private IDispatchMessageFormatter innerFormatter; public string ContentTypeOverride { get; set; } public WebContentTypeAttribute(string contentTypeOverride) { this.ContentTypeOverride = contentTypeOverride; } // IOperationBehavior public void Validate(OperationDescription operationDescription) { } public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { innerFormatter = dispatchOperation.Formatter; dispatchOperation.Formatter = this; } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { } public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { } // IDispatchMessageFormatter public void DeserializeRequest(Message message, object[] parameters) { if (message == null) return; if (string.IsNullOrEmpty(ContentTypeOverride)) return; var httpRequest = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name]; httpRequest.Headers["Content-Type"] = ContentTypeOverride; } public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) { return innerFormatter.SerializeReply(messageVersion, parameters, result); } }
而且你必须修改你的服务合同,看起来像这个
[OperationContract] [WebContentType("application/json; charset=utf-8")] public string DoWork(string FirstName, string LastName) { return "Your name is " + LastName + ", " + FirstName; }
正如您在此处所要求的,是一些描述这些WCF扩展的链接
IOperationBehavior接口
IDispatchMessageFormatter接口
如何实现IDispatchMessageFormatter
WCF可扩展性 - 插入自定义消息处理逻辑