jQuery $ .ajax对WCF服务的调用返回400 Bad Request

(最后更新)

我正在使用不熟悉的技术开发一个想法。 我写了一些WCF服务,但我从来没有做过任何高级配置。 这是我第一次深入了解jQuery。 前提是我创建一个WCF服务来获取分支信息,由jQuery检索。

我的第一次搜索产生了这个页面: http : //www.codeproject.com/KB/aspnet/WCF_JQUERY_ASMX.aspx#2我正在使用它作为我的代码的基础。 我最初是作为一个跨站点设置开始的,我摆脱了,看看我能不能让这个东西工作。 我搜索了堆栈溢出,没有post解决了我的400 Bad Request问题。

我的web.config中的代码:

                            

我的界面代码:

 [ServiceContract] public interface IGeoDataService { [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)] List GetBranches(); } // Use a data contract as illustrated in the sample below to add composite types to service operations. [DataContract] public class BranchData { [DataMember] public string BranchNumber { get; set; } [DataMember] public string BranchName { get; set; } [DataMember] public string StreetAddress { get; set; } [DataMember] public string City { get; set; } [DataMember] public string Zip { get; set; } [DataMember] public string State { get; set; } [DataMember] public string Phone { get; set; } [DataMember] public string County { get; set; } } 

jQuery脚本:

     /* help from http://www.codeproject.com/KB/aspnet/WCF_JQUERY_ASMX.aspx */ var varType; var varUrl; var varData; var varContentType; var varDataType; var varProcessData; function CallService() { // Thank you Bing: http://blueonionsoftware.com/blog.aspx?p=03aff202-4198-4606-b9d6-686fd13697ee jQuery.support.cors = true; $.ajax({ type: varType, url: varUrl, data: null, crossDomain: true, contentType: varContentType, dataType: varDataType, processdata: varProcessData, success: function (msg) { ServiceSucceeded(msg); }, error: ServiceFailed }); /* $.getJSON(varUrl, null, function (msg) { ServiceSucceeded(msg); }); */ } function GetBranchDataJson() { varType = "POST"; varUrl = "GeoDataService.svc/GetBranches"; varData = ""; varContentType = "application/json; charset=utf-8"; varDataType = "json"; varProcessData = true; CallService(); } function ServiceSucceeded(result) { var ddlResult = document.getElementById("ddlResult"); for (var j = ddlResult.options.length - 1; j >= 0; j--) { ddlResult.remove(j); } for (var i = 0; i < result.length; i++) { var opt = document.createElement("option"); opt.text = result[i].BranchName; ddlResult.options.add(opt); } } function ServiceFailed(jqXHR, errorType, errorThrown) { alert('error!\n' + jqXHR + '\n' + errorType + '\n' + errorThrown); }   

你会注意到我正在使用jQuery 1.6.1,而不是教程中的1.3。 教程在我的盒子上正常运行并按预期完成所有操作。 不幸的是,我的代码没有。 我感谢您提供的任何帮助。

哦,这是Fiddler请求的副本:

 POST http://localhost:16062/GeoDataService.svc/GetBranches HTTP/1.1 Accept: application/json, text/javascript, */*; q=0.01 Content-Type: application/json; charset=utf-8 Referer: http://localhost:16062/Default.aspx Accept-Language: en-us Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) Host: localhost:16062 Content-Length: 0 Connection: Keep-Alive Pragma: no-cache 

更新:好的,我传递了“{}”作为数据查询(显然这是向不带参数的方法传递任何内容的正确方法),现在我得到了不支持的媒体类型。 跟踪exception是:System.ServiceModel.ProtocolException:Content Type application / json; charset = utf-8被发送到期望text / xml的服务; 字符集= UTF-8。

调用本身似乎没有任何问题 – 您应该尝试启用跟踪以查看为什么WCF正在考虑传入的请求是坏的。 我尝试了类似的代码(见下文),它工作得很好。 此外,由于请求来自与服务相同的域(localhost:16062),因此您没有任何跨域问题。

更新:基于问题的评论主题的解决方案

web.config中元素的“name”属性必须与服务类的完全限定名称 (即命名空间+名称) 匹配 (即,.svc文件中使用的相同值)。 否则,您将获得为您的服务添加的默认端点 ,这可能是也可能不是您想要的 – 默认情况下,您将获得BasicHttpBinding端点,这不是您想要的端点。

此问题是.NET Framework 4.0中添加的function的一个不幸的副作用: 简化配置 。 在.NET 3.5之前,每个服务都需要在web.config上有一个条目来配置它,甚至最简单的应用程序(即hello world)的配置文件都很大。 所以,从4.0开始,如果WCF找不到名称与服务的完全限定名称匹配的服务元素,它会很高兴地认为您要使用默认配置。 这就是为什么它首先与WcfTestClient“合作”。

 public class StackOverflow_6526659 { [ServiceContract] public interface IGeoDataService { [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)] List GetBranches(); } public class Service : IGeoDataService { public List GetBranches() { return new List(); } } // Use a data contract as illustrated in the sample below to add composite types to service operations. [DataContract] public class BranchData { [DataMember] public string BranchNumber { get; set; } [DataMember] public string BranchName { get; set; } [DataMember] public string StreetAddress { get; set; } [DataMember] public string City { get; set; } [DataMember] public string Zip { get; set; } [DataMember] public string State { get; set; } [DataMember] public string Phone { get; set; } [DataMember] public string County { get; set; } } public static void Test() { string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); WebHttpBinding binding = new WebHttpBinding { CrossDomainScriptAccessEnabled = true }; WebHttpBehavior behavior = new WebHttpBehavior(); host.AddServiceEndpoint(typeof(IGeoDataService), binding, "").Behaviors.Add(behavior); host.Open(); Console.WriteLine("Host opened"); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress + "/GetBranches"); req.Method = "POST"; req.GetRequestStream().Close(); HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription); foreach (var header in resp.Headers.AllKeys) { Console.WriteLine("{0}: {1}", header, resp.Headers[header]); } if (resp.ContentLength > 0) { Console.WriteLine(new StreamReader(resp.GetResponseStream()).ReadToEnd()); } Console.Write("Press ENTER to close the host"); Console.ReadLine(); host.Close(); } }